eight months agoStyling buttons to look like links

A common mistake that many developers make is to use a link to trigger an action on the server, for example deleting an item from a shopping basket or adding something to your favourites. Both of these examples are actions that modify state on the server and should therefore be performed using 'post'.

However, sometimes even developers who know that is wrong to use a link where they should be using a form, get sucked in to doing so when the design requires a button to look like a link.

Please note that I am definitely not encouraging the redesign of button elements to look like links. I believe that we shouldn't mess too much with browser defaults for functional things like form controls, scroll bars and the like. That said, sometimes you just have to build what your designer tells you to.

It actually isn't hard to make a submit button look like a link using CSS so you should never find yourself in a position where you have to sacrifice forms for links purely for the sake of the design.

Firsly the markup: although you can use an input type="submit" as a submit element and this example would work in the same way, the button element is, in my opinion, a much better option. It is really flexible and can have a variety of different elements nested inside if you so choose, from simple text with an image right through to headings and paragraphs. This article on buttons by Aaron Gustafson back in 2006 is still fairly relevant today and explains some of the uses the humble button element can be put to.

Another useful article also from a while ago explains the techniques that Wufoo use to style links to look like buttons. The really important thing to take away from this article is that putting overflow: visible on a button fixes the crazy width issue that IE likes to deal us.

I have posted a simple demo for you to follow along in your browser. For the purposes of this example the markup will be:

<form action="#" method="post">
	<p><button type="submit" class="link"><span>Hello there I am a button</span></button></p>
</form>

<p><a href="#">That's nice, I am a link</a></p>

The basic page in this demo has the following styles applied to the links and body:

body {
	font-family: "Verdana" sans-serif;
}
a:link,
a:visited { 
	color: blue;
}
a:hover,
a:focus,
a:active {
	color: black;
}

Next I add the magical incantation to kick the width in IE for all buttons:

button {
	overflow: visible;
	width: auto;
}

I have added a class of link to the button that I wish to style as a link element and the basic styles that I apply to this are the colour and font family (the button seems to inherit system font settings), as well as over-riding the button defaults with regards to border, margin, padding and background.

The default cursor for button elements is a regular arrow. I normally set cursor: pointer for all button elements to ensure the user knows they are clickable. This makes even more sense for buttons that are pretending to be links.

button.link {
	font-family: "Verdana" sans-serif;
	font-size: 1em;
	text-align: left;
	color: blue;
	background: none;
	margin: 0;
	padding: 0;
	border: none;
	cursor: pointer;
}

Interestingly, Mozilla won't let you select the text of the button element like other browsers will, so to override this and enforce that the user can select the text of our psuedo-link, you can apply the following as well:


	-moz-user-select: text;

You can also choose to override all your other button styles if there are any.

Now you almost have a link. Those of you paying close attention earlier on will have noticed an as yet unexplained inner span to our button. This is because it does not appear to be possible to set text-decoration on a button directly and depending on how you have your link styles set this is something you are likely to want to do.

The text-decoration: underline rule is actually applied to the span on hover or focus of the button. This way is more flexible if you choose at some point to add or remove an underline on hover.


button.link span {
	text-decoration: underline;
}
button.link:hover span,
button.link:focus span {
	color: black;
}

Naturally everybody's 'favourite' browser, Internet Explorer six will not display the hover effect on your link because it doesn't 'do' hover on arbitrary elements, only on actual links. You can fake this effect with Javascript if you really wish, adding a class on hover and removing it on mousout. Other limitations of this technique are that selection of text looks a bit dodgy in all versions of IE.

My example above is very simple. If you wath a button that appears in flow with text as a link, for example the delete link on a shopping basket item in this example, you will also need to apply 'display:inline' to both the form and any block level elements inside.

So there you have it, no excuses now — go forth and use the correct HTTP method!

19 comments

  1. Very nice!

    One question: couldn't you use an anchor element (sans attributes) inside the button element instead of a span? Not terribly semantic, but might it solve the problem of hover on IE?

    David Lindquist 10th June 2009 02:14permalink.

  2. Imo there are good usecases of styling buttons as links. Submit/Cancel for example. Make the submit button look like a button and make the cancel button look like a link so that the submit button stands out.

    Andreas 10th June 2009 08:04permalink.

  3. Great to have this technique documented, buttons are a real pain to style.

    However, using the <input /> element may be safer. IE doesn't distinguish between the button element that was pressed, and other button elements in the form.

    IE will tell the server that all buttons in the form were pressed (btnname=save&btnname=delete), which is less than helpful.

    Jake Archibald 10th June 2009 09:04permalink.

  4. Great tutorial Nat.

    This is something that has bugged me in the past and I've only been able to half emulate.

    Now all we need is for HTML to support PUT and DELETE, then we can actually use the right HTTP methods.

    Steve Anderson 10th June 2009 09:23permalink.

  5. Nice article, CSS hacking at it's best!

    But would you consider using JavaScript to hide the submit button, and replace it with an <a> element that simply triggers the form submit event? Leaving an unstyled, but functional button if JavaScript is off, and an easier to style cross-browser wise if JavaScript is on.

    Cheers

    Daniel 10th June 2009 09:23permalink.

  6. Nice sensible tip, and something I've been doing for a while.

    The only problem I've found is when you want to present several 'links' in a row (for example in a table row), where some are actual A links and some are link-styled buttons - the baseline for the text does not line up properly for the two different elements without some browser-specific padding.

    Matthew Pennell 10th June 2009 11:35permalink.

  7. Hi Natalie,

    You may want to add following CSS to remove excess padding from buttons in Gecko (Firefox).

    button::-moz-focus-inner{
      padding:0;
      border: 0;
    }

    The difference may be small, but it will get you as close to normal anchor tag as possible. You can see live demo I prepared too. The pseudoelement is present in both button and input[type="submit"] elements.

    Peter 10th June 2009 11:57permalink.

  8. FWIW, here is a quick-and-dirty JQuery implementation of the JavaScript-only approach suggested by Daniel:

    $(document).ready(function() {
        $('input.link[type=submit]').each(function() {
            var text = $(this).val() || 'Submit';
            var form = $(this).parents('form').get(0);
    
            var a = document.createElement('a');
            a.appendChild(document.createTextNode(text));
            a.setAttribute('href', '#');
    
            $(a).click(function() { form.submit(); return false; });
    
            $(this).replaceWith(a);
        });
    });

    David Lindquist 10th June 2009 17:46permalink.

  9. Re: Jake's comment, Coping With Internet Explorer's Mishandling of Buttons highlights two problems with the <button> element and Internet Explorer:

    1. Internet Explorer will send the innerHTML (or maybe innerText) of the <button> instead of the value attribue (which is what other browsers send). This affects at least IE 6 and IE7.
    2. IE 6 appears to send the innerHTML/Text of every <button type="submit">, not just the one that was clicked, which makes it really difficult for the server to work out what the user wanted to do.

    Walter Rumsby 10th June 2009 23:05permalink.

  10. For the purposes of this example the markup will be:

    <p><a href="#"That's nice, I am a link</a></p>

    Missing something there. :p

    Craig 11th June 2009 03:00permalink.

  11. Jon Tan did something similar a while ago:

    http://jontangerine.com/silo/html/button/

    The note there is still relevant, for anyone considering this sort of thing:

    "Note: Users expect that form controls will look like form controls. Therefore, it is not recommended to alter a form button (or any other form control) in this way unless you deem it absolutely necessary. This is a proof of concept only as the use of links for user controls is currently so prevalent."

    Chris Shiflett 11th June 2009 04:23permalink.

  12. Imaging if you could do it without the form

    <button class="link"><span>Hello there I am a button</span></button>

    wouldnt that be great.

    kaare 12th June 2009 10:18permalink.

  13. Nice work Nat!

    Incidentally, have you come across a way to style <button> tags without using special CSS for IE and Firefox? I've used Derek DeVries approach at http://derekdevries.com/2009/04/02/custom-buttons-with-css/, but it's not clean!

    Terry 15th June 2009 11:40permalink.

  14. Great work Nat and thanks for linking up that old article of mine too!

    Aaron Gustafson 18th June 2009 16:13permalink.

  15. Great work Nat,

    In my case, I've been solving this issue by using <label><input type="submit"... instead of a <button><span>

    the label tag will trigger a form submit on the input and this approach is fully stylable.

    The only problem I've found is that on 508 section a label tag should have text in it, but as far as I know we can solve by adding a title attribute.

    <label class="button" title="Save your settings"><input type="button" name="SaveSettings" /></label>

    You could hide the input through visibility:hidden and just use image background on the label. Or you can use sliding doors techniques to use the input text.

    André Cassal 22nd June 2009 16:22permalink.

  16. A while back I took the "use JS to swap out submit buttons with easily styleable links" approach and wrote it up here:

    http://www.kelvinluck.com/2009/02/progressive-enhancement-with-jquery-example/

    May be interesting as an alternative approach...

    Kelvin Luck 23rd June 2009 15:37permalink.

  17. But when you click on the link it still shows an impression (kind of a clicking effect) that it is a button. How can we get rid of that?

    Saravanan 14th December 2009 18:54permalink.

  18. The professional <a href="http://www.topdissertations.com">thesis</a> will be yearned-for by people in the world but in academic life they require the <a href="http://www.topdissertations.com">dissertation service</a> or just define dissertation as this topic.

    KonnieDg24 30th January 2010 03:03permalink.

  19. @André Cassal

    Unfortunately this doesn't work with Opera. :/

    tolan 2nd February 2010 16:14permalink.

Line breaks are preserved; URLs will be converted in to links.

Enter your own, valid XHTML. Allowed tags are: a, p, blockquote, ul, ol, li, dl, dt, dd, em, strong, dfn, code, q, samp, kbd, var, cite, abbr, acronym, sub, sup, br, pre

10th June 2009

You are reading "Styling buttons to look like links" written by Natalie Downe on the 10th of June 2009 at 12:47 am.

Next: CSS Selector reference guide

Previous: Dinky pocketbooks: the command-line reference edition