Button, button, where is the button?

Creating a Rollover Button without Javascript

JavaScript rollover buttons have been a common feature on the web for a long time now, but they do have some drawbacks. In the article below I will describe a way to make some neat looking rollover techniques with just XHTML and CSS. They aren't perfect for every situation, but they are an interesting alternative.

Why not just use MM_swapImage()?

Macromedia's (now Adobe's) ubiquitous JavaScript functions for rollovers are effective but they do have a few disadvantages:

First, they are usually custom graphics which make them time consuming to make and modify. Also, search engines may not be able to read them. Search engines place a lot of weight on the text of links, so unless you are careful about using alt and title attributes on your buttons you may not be providing valuable information.

In addition if you don't provide alternate text for your buttons, you are not meeting standard accessibility guidelines. This means that a disabled visitor using a screen reader might not be able to use your navigation at all.

Also, there are a still a lot of internet users that don't have Javascript turned on. I block JavaScript on untrusted sites for security and to prevent annoying advertisements. So, as a personal challenge I thought I would see how far I could get without Javascript. It turns out I could get pretty far.

The Basics

You should already know this, but just in case you don't in order for any CSS to behave predictably you need to set your DOCTYPE. This tag should be the very first thing on the top of your page. For these examples I am using XHTML 1.0 Strict.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

I am going to skip the other basic tags you should have, like <html />, <head /> and <body />. Hopefully you know how to use those already.

Next, lets set up a basic link and explore how a rollover works.

<a href="#">example 1</a>

The code above would produce this:

Which is not very exciting. So, let's kick it up a notch by adding some CSS.

<style type="text/css">
  a.example02 {
    color: #FFCD08;
    background: #000000;   
  }
  a.example02:hover {
    color: #000000;
    background: #FFCD08;
  }
</style>
<p>
  <a href="/web/20090305142102/http://irolo.net/rollover_button#" class="example02">example 2</a>
</p>

This looks a little more like a button. We should add some padding and margins, but there is another problem to consider. What happens if the text of the links are not the same length?

<style type="text/css">
  a.example03 {
    padding: 0.2em;
    margin: 0.2em;
    color: #FFCD08;
    background: #000000;   
  }
  a.example03:hover {
    color: #000000;
    background: #FFCD08;
  }
</style>
<p>
  <a href="#" class="example03">short</a>
</p>
<p>
  <a href="#" class="example03">a bit longer</a>
</p>

Trying something different

As you can see, styling just an anchor doesn't work. For one thing they are inline elements, so you can't safely set their width and height. So far I have been deliberately using awkward code to make a point, but I'm sure you've already guessed that we are going to need to use <div /> tags to do what we want. Let's try it out.

<style type="text/css">
  div.example04 {
    text-align: center;
    padding: 0.2em;
    margin: 0.2em;
    background: #000000;
    width: 150px;  
  }
  div.example04 a {
    color: #FFCD08;
  }
  div.example04:hover {
    background: #FFCD08;
  }
  div.example04:hover a {
    color: #000000;
  }
</style>
<div class="example04">
  <a href="#">short</a>
</div>
<div class="example04">
  <a href="#">a bit longer</a>
</div>

Unfortunately, the example above still doesn't work. If you look at this in Internet Explorer, it doesn't work at all. This is because IE doesn't support the hover pseudo-class on most elements. On the other hand if you are using Firefox, you will see the rollover effect, but the link will only be active if you roll over the text.

A "real" button

In order to solve the problems mentioned above, I had to actually nest one <div /> tag inside another with the anchor in-between. More importantly, I had to make CSS that would work in both Firefox and IE without any hacks. Take a look at the example below:

<style type="text/css">

  #div.outy_button {
    text-align: center;
    margin: 0.2em;
    background: #000000;
    width: 150px;  
  }
  div.outy_button a {
    color: #FFCD08;
    background: #000000;
  }
  div.inny_button {
    padding: 0.2em;
    width: 150px;
  }

  /* This is for Firefox */
  div.outy_button:hover {
    background: #FFCD08;
    color: #000000;
  }

  /* This is for IE */
  div.outy_button a:hover {
    cursor: pointer;
    background: #FFCD08;
    color: #000000;   
  }

</style>
<div class="outy_button">
  <a href="#">
    <div class="inny_button">short</div>
  </a>
</div>
<div class="outy_button">
  <a href="#">
    <div class="inny_button">a little longer</div>
  </a>
</div>

Surprisingly this works, and although I have only mentioned Firefox and IE, as of the publication date of this article, this also works in Safari and Opera for both Mac and PC.

But, that's not a button!

So far we have been dealing with solid colors, but you can use background graphics with CSS to create all kinds of neat effects. Check out these samples:

<style type="text/css">

  div.out05 {
    text-align: center;
    font-weight: bold;
    margin: 0.2em;
    background: #000000 url("/images/rollover_button/up.gif") top left no-repeat;
    width: 150px;
    height: 30px; 
  }
  div.out05 a {
    color: #FFCD08;
  }
  div.in05 {
    padding: 5px 0px;
    width: 150px;
    height: 20px;
  }

  /* This is for Firefox */
  div.out05:hover {
    background: #FFCD08 url("/images/rollover_button/over.gif") top left no-repeat;
    color: #000000;
  }

  /* This is for IE */
  div.out05 a:hover {
    cursor: pointer;
    background: #FFCD08 url("/images/rollover_button/over.gif") top left no-repeat;
    color: #000000;   
  }

</style>
<div class="out05">
  <a href="#">
    <div class="in05">short</div>
  </a>
</div>
<div class="out05">
  <a href="#">
    <div class="in05">a little longer</div>
  </a>
</div>
<style type="text/css">

  div.out06 {
    text-align: right;
    font-weight: bold;
    margin: 0.2em;
    background: #FFFFFF url("/images/rollover_button/ponies_up.gif") top left no-repeat;
    width: 146px;
    height: 26px; 
  }
  div.out06 a {
    color: #FF00FF;
  }
  div.in06 {
    padding: 3px 30px;
    width: 86px;
    height: 20px;
  }

  /* This is for Firefox */
  div.out06:hover {
    background: #FF00FF url("/images/rollover_button/ponies_over.gif") top left no-repeat;
    color: #FFFFFF;
  }

  /* This is for IE */
  div.out06 a:hover {
    cursor: pointer;
    background: #FF00FF url("/images/rollover_button/ponies_over.gif") top left no-repeat;
    color: #FFFFFF;   
  }

</style>
<div class="out06">
  <a href="#">
    <div class="in06">omg!</div>
  </a>
</div>
<div class="out06">
  <a href="#">
    <div class="in06">lol :)</div>
  </a>
</div>

One of the greatest strengths of this method is that you can add a new button to your page, or change the text of a button all without creating new images. This is really great for dynamically generated content and I have used solutions like this on many CMS sites I have created. However…

Caveats

… there are a few disadvantages. There always are. First, the text of these buttons is real HTML text. That means that it may not always look exactly like you want it to. If the visitor's browser has unusual settings the whitespace might not look even, or if the text gets too big it might run right off the button. You also have less control over what fonts you can use and you can't reliably add special effects like drop shadows or borders to your text like you could with a graphical button.

Second, and possibly more important, this code is not technically XHTML compliant. At least according to W3C tests. Apparently this code fails because <div /> tags should not be nested inside of anchor <a /> tags. However as I said before, this does render properly in most browsers and I don't think it would cause any accessibility problems. So, I'm not going to worry too much about it.