MightyMeta

fading-button-bg-b

Fading Button Backgrounds 2

| 68 Comments

When Firefox 4 is released this October, February? browsers that support the CSS3 transition property will make up approximately 30% of the market (providing current Firefox users upgrade). With this in mind, it now becomes viable to consider CSS as an alternative to using JavaScript to achieve fading :hover effects on buttons and other interface elements.

Why CSS?

A popular method for fading background images is the ‘Pufferfish’ technique which uses JQuery to append an additional <div> or <span> element to the HTML and animate the fade on :hover using the opacity property. The main issue with this, apart from the reliance on non-semantic HTML, is that the opacity property is inherited by any children of the element that it is applied to. In other words, if you make a button fade on :hover, then any web text that it contains also vanishes.

Here is an example of this problem.

Dragon Interactive, authors of Pufferfish, got around this by using images for text, but this isn’t ideal as it makes pages harder to update, rules out fun with @font-face, and is not so good for accessibility.

I had a go at solving this a couple of months ago, and sort of gave up as the only solution seemed to involve absolute positioning using buttons of fixed sizes, which isn’t suitable for most layouts. I also couldn’t get Internet Explorer to work with it at all (IE Issues now resolved).

Below is where I’ve got to so far using CSS3 transitions to achieve the same result. I’m much happier with this because it involves no extra HTML and just a few lines of CSS. It’s a work in progress, and still has some caveats, but it seems like a more elegant solution.

Why Background Images?

Recently there has been a bit of discussion as to how CSS3 could reduce or even eliminate the need for images in web page designs. This is due to new properties that enable things such as rounded corners, drop shadows and gradients to be created procedurally with CSS rather than in an image editor. These methods can go a long way but have their limits if working with a design that requires any sort of texture or complex shading. If this is the case, then background images must be used.

Fading between two background images is problematic however. Both JavaScript and CSS3 animations rely on changing numerical values incrementally over time. This works well if you want to move or rotate an element using XY coordinates, or even change a colour using RGB or HSL, but the value for the background-image property is a text string, a URL, so you can’t animate it. opacity has a numeric value, but then you have the issue of web text vanishing.

I looked into inserting additional <span> elements but this doesn’t work so well with CSS as it does with JavaScript, because the :hover pseudo class can not be made to target elements other than those it has selected. To cut a long explanation short, the button text covered up the <span> and prevented it from fading.

Therefore my solution to date codges together a bit of CSS3 transitions with another CSS3 property, rgba, which allows us to animate an element’s opacity without affecting contained elements, but only works on solid colours.

Demo

Download Source Files

Compatibility

  • Firefox 4+, Chrome 4+, Safari 4+ — full support
  • Firefox 3, Chrome 1–3, Safari 3, Opera 9+*, Internet Explorer 9+rgba support only
  • The rest — fallback

*Note: Opera’s current support for the CSS3 transitions module is partial, and doesn’t as yet extend to working with opacity. Info on Opera’s support for transitions is here.

Tutorial

1. First of all, create a background image in your preferred image editor. Below is the one used in this example:

Background Image

You’ll notice that this is a sprite, and that it is fairly large to accommodate text resizing. Neither of these techniques are essential to this method, but are advisable for general site performance and accessibility.

2. Create a standard unordered list for the menu.

<ul id="nav">
   <li><a>Home</a></li>
   <li><a>About</a></li>
   <li><a>Gallery</a></li>
   <li><a>Contact</a></li>
</ul>

3. Style the list in the usual fashion, setting the background image for both the normal and :hover{} states.

#nav {
margin: 0;
padding: 0;
list-style-type: none;
}

#nav li {
display: block;
float: left;
margin: 0 5px;
}

#nav a {
display: block;
padding: 25px 35px;
font-family:Arial, sans-serif;
font-size: 1.2em;
font-weight: bold;
color: #fff;
text-decoration: none;
text-align:center;
background: url(../images/bg.jpg) no-repeat center -200px;
}

#nav a:hover {
background: url(../images/bg.jpg) no-repeat center top;
}

So far this should look identical in every browser:

Fading Menu Step 3

4. Now we can add some CSS3 decorations. These will display in Firefox 3.5+, Chrome, Safari 4+ and Opera 10.5+ and Internet Explorer 9+. Older browsers will default to how the buttons look in step (3).

#nav {
margin: 0px;
padding: 0px;
list-style-type: none;
}

#nav li {
display: block;
float: left;
margin: 0 5px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
-o-border-radius: 10px;
border-radius: 10px;
-moz-box-shadow: 1px 1px 1px #666;
-webkit-box-shadow: 1px 1px 1px #666;
-o-box-shadow: 1px 1px 1px #666;
box-shadow: 1px 1px 1px #666;
}

#nav a {
display: block;
padding: 25px 35px;
font-family:Arial, sans-serif;
font-size: 1.2em;
font-weight: bold;
color: #fff;
text-decoration: none;
text-shadow: 1px 1px 1px #666;
text-align:center;
background: url(../images/bg.jpg) no-repeat center -200px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
-o-border-radius: 10px;
border-radius: 10px;
}

#nav a:hover {
background: url(../images/bg.jpg) no-repeat center top;
}

Fading Menu Step 4

5. Finally, the code for the fading transition is added. How this works will be explained below:

#nav {
margin: 0px;
padding: 0px;
list-style-type: none;
}

#nav li {
display: block;
float: left;
margin: 0 5px;
background: url(../images/bg.jpg) no-repeat center top;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
-o-border-radius: 10px;
border-radius: 10px;
-moz-box-shadow: 1px 1px 1px #666;
-webkit-box-shadow: 1px 1px 1px #666;
-o-box-shadow: 1px 1px 1px #666;
box-shadow: 1px 1px 1px #666;

}

#nav a {
display: block;
padding: 25px 35px;
font-family:Arial, sans-serif;
font-size: 1.2em;
font-weight: bold;
color: #fff;
text-decoration: none;
text-shadow: 1px 1px 1px #666;
text-align:center;
background: url(../images/bg.jpg) no-repeat center -200px;
background: rgba(80, 125, 200, 0.55);
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
-o-border-radius: 10px;
border-radius: 10px;
-webkit-transition: background 0.5s linear;
-moz-transition: background 0.5s linear;
-o-transition: background 0.5s linear;
transition: background 0.5s linear;
}

#nav a:hover {
background: url(../images/bg.jpg) no-repeat center top;
background: rgba(100, 125, 175, 0);
}

Three things have happened here.

Firstly, on line 11 of the code above, an additional background property has been added to #nav li, giving it the same background image as #nav a:hover.

Secondly, additional background properties with rgba values have been set for both #nav a and #nav a:hover. rgba lets us set a solid bluey-grey colour for a background, and also specify an alpha transparency level, from 1 (fully opaque) to 0 (fully transparent).

In this example, the :hover rule set to 0, whereas #nav a is given the value of ‘0.55′. This makes the bluey-grey colour semi-opaque and allows the textured image declared in #nav li to show through, appearing darker and greyer than normal.

The difference between these two opacity values can now be animated, giving a fading image effect.

Apart from not being inherited by child elements, the rgba property is useful because if the browser recognises it, the solid colour will be used in place of the background image originally declared in that rule. Yet if the browser doesn’t support rgba, the background image remains intact, allowing you to create fallbacks for older browsers without the use of hacks, conditional comments or browser detection scripts.

Thirdly, the transition properties for each vendor are added on lines 39–42. The syntax in this case is pretty straightforward:

transition: background 0.5s linear;

‘background’ specifies the property that you want to animate.

‘0.5s’ states how long you want the animation to last for, in seconds (more intuitive than JS’s milliseconds? — discuss…)

‘linear’ specifies the timing of the transition. It is possible to create ease-in and ease-out timings. The current state of the W3C spec regarding transition timing is here and a useful tutorial/demo by Richard Bradshaw can be found here. Linear is the bog-standard default option.

Here’s a link to a demo of the final result again:

Demo (best viewed in FF4, Chrome or Safari)

Conclusion

The result isn’t a true fade between two background images (the only way to achieve this cross-browser is using JS using this method), but it does give the impression of being so, and allows us to create flexible buttons with a bit of texture, without extra markup. What it can’t do is simulate a fade between two completely different images, oh well :(

The menu can be edited dynamically by simply altering the HTML, which means it can be incorporated into a CMS template, can be enlarged for disabled users and is screen reader and search engine friendly. It also reverts back to a non-fading version if browser support isn’t there, which at the moment will be about 70% of the time, although this will improve as adoption of the transition property increases.

If you enjoyed this post, please consider sharing it using the above buttons, leaving a comment or subscribing to the RSS feed.

68 Comments

  1. Yes now CSS3 supports all Firefox 3.5+, Chrome, Safari 4+ and Opera 10.5+ and Internet Explorer 9+.

  2. Thanks for your valuable post.

  3. Thanks for sharing this post very clearly with images and codings.

Leave a Reply

Required fields are marked *.


MightyMeta, 8 St Lawrence Lane, Ashburton, Devon, UK, TQ13 7DD

Powered by WordPress | Theme Derived From "Yoko" by by Elmastudio

Scroll To Top