Changing a Background-image with CSS3 Transitions

by Stephanie Rewis on March 1, 2011

As you may have read, outside of gradients, you can’t change a background-image with CSS transitions. Or can you? At InControl Conference last week, Greg Rewis spoke about Transitions, Transforms and Animations. A question was asked about showing one background-image on load and transitioning to another in a subsequent pseudo-state. You can always change the background (we do it all the time in menus on :hover), but you can’t apply sexy transitions to that change. You can, however, transition a background position change. In the first demo, I’ve created a sprite that has both background states which load with one image, and then move to the other when the pseudo-state is triggered:

CSS Transition with sprite

(Thanks for your nice use of this effect at the bottom of CSS Tricks, Chris Coyier!)

In the InControl wrap up panel, someone asked a question about creating a menu that has no background image to start, but on hover, would transition to the background image. While it’s correct that you can’t do exactly that, all good CSS’ers know there’s usually a clever work around. An idea occurred to me on stage that I’ll share here. Using a sprite again, have the starting portion of it transparent (gif or png). You can create the effect of going from no background to a background image by simply changing the background-position.

Illusion of going from no background to an background-image using CSS3 transitions.

What creative uses can you think of for CSS transitions and background images?

{ 16 comments… read them below or add one }

Patrick Haney March 1, 2011 at 12:28 pm

Interesting how sprites come to the rescue once again. I love Chris’s implementation on CSS Tricks, along with transitioning the background color. Really nice work, and gets me thinking about how I can implement something similar…

Chris Coyier March 1, 2011 at 12:43 pm

Classic example of where pseudo elements *could* have saved us, but alas, the ability to transition them is relegated to only Firefox 4 so far. If people are interested in a fade effect rather than slide (while still using a sprite) that can be done a number of ways (see:

Stephanie (Sullivan) Rewis March 1, 2011 at 1:38 pm

@Patrick – Yes, I love Chris’s as well.
@Chris – thanks for linking to that tutorial. I missed it since I was out in the ocean on a boat somewhere without internetz (shocking, I know!).

Ilia March 1, 2011 at 1:39 pm

Hmmm, that’s an interesting idea. First thing I thought of as I was reading this was animation frames. If you have a small image and don’t require a very smooth animation you can animate a PNG by using a single background image and CSS keyframe animations. Not sure how useful it is really, but here is kind of an awkward example.
Despite the simplistic animation the two things to note here are, the ball is a PNG image thus doesn’t have the GIF limitations, and because of that, background colour is CSS controlled and can be anything.
Of course it’s also laggy and has some “artifacts”, so there you go, take it for what it is. :)

Stephanie (Sullivan) Rewis March 1, 2011 at 2:12 pm

@Ilia – I think animations (especially when more than just -webkit- support exists) will open up all sorts of possibilities. I look forward to the day…

Robb Hartzog March 1, 2011 at 2:31 pm

I actually use a CSS transition for the left menu on my site. A single image used as the background of a DIV tag placed correctly using height and width. Then on hover, you just change the position and it slides to my “mouse-over” image. If you look at the CSS its only loading one image for all my menu items and mouse overs. One thing I love about it is that you no longer have that flicker you get sometimes in IE when using your typical JavaScript image swap technique.

Andrew Horth March 1, 2011 at 5:10 pm


I’ve been having some fun with this and have a few slightly over the top examples which are essentially just animating the background position of multiple backgrounds.
The first one uses nested divs and animates each of their backgrounds at different speeds (hence parallax)
The second animates multiple backgrounds on a single div.

Hope it at least brings a smile :)

PS and yes I know my website isn’t exactly ‘finished’!

Stephanie (Sullivan) Rewis March 1, 2011 at 5:50 pm

@Robb – Did you set actual transitions? Or did you let it do an instant replacement on the :hover pseudo-class (or use JS for the transition)?
@Andrew – Ahhh, animations. Cute. Yes, that’s a lot more complicated than my transitions example (and sadly, not yet anywhere but Webkit). As to your site—I have tons to do to mine. Only bored web devs have time to work on their own sites. ;)

Oli Studholme March 1, 2011 at 10:18 pm

Are gradient transitions actually working anywhere yet? also gradient and image transitions are specced in so here’s hoping that this will lead to background-image images returning to the list of transitionable properties soon.

Javier Usobiaga (@htmlboy) March 15, 2011 at 11:41 am

Hi, I’ve found a workaround for “dissolve” transitions on background images:

It makes use of CSS content and works only on solid backgrounds… but works on Gecko & Webkit browsers :-)

Stephanie (Sullivan) Rewis March 17, 2011 at 10:11 am

@Javier – While that solution doesn’t work to change one background image to another, it’s a creative solution to showing a background image on hover. I like. :)

Asaf Bochman April 6, 2011 at 1:06 pm

So I’ve been building a small subnav on one of our landing pages and came up with a way to transition from one background to another with a fallback for IE.

The markup is simple:

The css is a bit more but basically puts two layers of background images and animating the opacity on hover. This can be modded for IE after adding this to the :hover state of the anchor.

element {
background-image:hover image; // This will be shown on hover.

a {
background-image:non-hover image; // This will be shown during all states except hover

a:hover {
filter:alpha(opacity=0); // For IE
opacity: 0; // For modern browsers
// Animates the opacity of the anchor image revealing the image underneath contained in the element.


I don’t have too much time to mess around but I believe this might also be achievable with the new CSS3 psuedo class “:before” instead of using an additional element.


Dustin Gardner January 3, 2012 at 7:37 am

On the sprite image transition (First Link) I’m looking to make the size about 1005 pixels wide, and 150 pixels tall. The changing of the actual area was easy, but how would I get the image to fit correctly here as well? This involves moving the transitional image over more, creating a larger image altogether, and then positioning it differently as well. I’m not the best when it comes to mathematics of this nature, so could someone give me some pointers here?

anonymaus June 20, 2012 at 3:39 pm

a hack for transitioning between normal and hover states would be putting the hover image as the background image for the link set at zero opacity, on top of the div under it that has the normal state background image. then, on hover, the opacity transitions to 100 and back out.

#msgbtnbg { width: 160px; height: 46px; background: url(../images/msg_normal.png) center top no-repeat; }

#msgbtn { width: 160px; height: 46px; background: url(../images/msg_up.png) center top no-repeat;
filter:alpha(opacity=0); opacity: 0; -webkit-transition: opacity 0.2s linear; -moz-transition: opacity 0.2s linear; -o-transition: opacity 0.2s linear; transition: opacity 0.2s linear;}

#msgbtn:hover, #msgbtn:focus { filter:alpha(opacity=100); opacity: 100; }

#msgbtn:active { background: url(../images/hdr-msg_down.png) center top no-repeat; }

dont forget to pre-load images somewhere else on the page with something like:

anonymaus June 20, 2012 at 3:40 pm

div style=”display:none”
img src=”../images/hdr-msg_up.png” alt=”" /
img src=”../images/hdr-msg_down.png” alt=”" /
img src=”../images/hdr-twitter_up.png” alt=”" /
img src=”../images/hdr-twitter_down.png” alt=”" /

anonymaus June 20, 2012 at 3:46 pm

and the html would look something like this:

div id=”msgbtnbg”
a href=”/contact” id=”msgbtn” title=”"

Leave a Comment

{ 5 trackbacks }