Grow your CSS skills. Land your dream job.

Garage Door Style Menu

Published by Chris Coyier

Originally published on July 21, 2008 as only a jQuery technique. Now updated to include CSS3 and a combo technique which is mo' betta.

A garage door style menu is where an image (the "door") slides up to reveal something behind it. We'll do this in two ways, with CSS3, and with jQuery. Then we'll combine them into a progressive enhancement way to handle it.

The jQuery Method

Right out of the box, jQuery provides the animate function, which allows us to morph some CSS attributes over time. Things like opacity, font-size, width, length, margin, and padding, basically anything where you set the value with a number is supported. There are a couple of notable limitations to this function though, and one of those is "background-position".

Thankfully, there is a plugin to help with this, the Background-Position Animation Plugin by Alexander Farkas. (direct link to JS). With this, we can do some fun stuff! NOTE: This plugin seems to work great with jQuery 1.2.6, but broke when I tried the lastest-as-of-this-writing 1.4.3.

View Demo   Download Files

1. Creating the image needed

We are going to need three different types of images here. First is a background image for the entire menu itself. This is going to be one big image for the entire menu which will be the imagery which is "revealed" when the door opens. Check out my Photoshop file:

Notice my guides. I have these set up as a visual reference to what the "viewable area" is going to be within the garage frame. Note that the Photoshop files are included in the download for your reference. Combining this into one graphic saves HTTP requests, like CSS Sprites.

Second, we'll need to create the garage doors which we will call the "shutters". These need to be separate graphics as each one will need to be animated separately. I made a separate template for this, so I could again use guides to keep things as close to centered and nicely spaced as possible.

Lastly, we need a window which will act as the garage frame. This is the nice touch that really ties the whole idea together. Since this is going to be the top-most layer, we will apply this to the anchor links themselves, so that they can be clickable with unique URLs.

2. Writing the HTML markup

Of coure, no matter how fancy we want to get with our menus, the markup should be clean and semantic so that with CSS and/or JavaScript disabled, the menu still looks and behaves like a menu.

Here is the menu markup:

<ul id="garagedoor">
  <li id="shutter1"><a href="#1">Link 1</a></li>
  <li id="shutter2"><a href="#2">Link 2</a></li>
  <li id="shutter3"><a href="#3">Link 3</a></li>
  <li id="shutter4"><a href="#4">Link 4</a></li>

The ID on the menu will give us all the specificity we need. Notice though that each shutter has it's own ID. This is just so that each menu item can have it's own door graphic, so we'll use that as a hook. You could also use something like :nth-child() here, but since we're shooting for good cross-browser compatibility we'll skip that. With CSS turned off, we have a very functional menu:

3. The CSS

Here I'll show you the whole CSS file, and then point out a few things below:

#garagedoor {
  margin: 50px auto;
  list-style: none;
  background: url(../images/menu-bg.jpg);
  width: 800px;
  overflow: auto;	

#garagedoor li {
  width: 200px;
  height: 100px;
  display: block;
  float: left;

#garagedoor li#shutter1 {
  background: url(../images/shutter-africanplains.jpg) no-repeat; 
#garagedoor li#shutter2 {
  background: url(../images/shutter-reptiles.jpg) no-repeat; 
#garagedoor li#shutter3 {
  background: url(../images/shutter-aviary.jpg) no-repeat; 
#garagedoor li#shutter4 {
  background: url(../images/shutter-arcticzone.jpg) no-repeat; 

#garagedoor a {
  width: 200px;
  height: 100px;
  display: block;
  background: url(../images/window.png) no-repeat bottom center;
  text-indent: -9999px;

The menu background is applied to the UL itself. Then each list item is set to a specific width and height (same height each individual "reveal" graphic) and floated to the left (for a horizontal menu). The ID values on the LI items are used to apply the separate background graphics only. The anchor links, as I mentioned above, will be the top-most layer and thus use the window overlay. These will need to be set as a block level element, have with and height applied, and use text-indent to kick the text off the page.

4. The jQuery JavaScript

First things first, we include the latest version of jQuery on our page, as well as the plugin I linked to at the top of this article. Then we can write the jQuery JavaScript needed to make the garage door effect happen.

$(function() {

	// Set CSS for old versions of Firefox (Required to use the backgroundPosition js)
	$('#shutter1').css({backgroundPosition: '0px 0px'});
	$('#shutter2').css({backgroundPosition: '0px 0px'});
	$('#shutter3').css({backgroundPosition: '0px 0px'});
	$('#shutter4').css({backgroundPosition: '0px 0px'});

	// Animate the Shutter  
	$("#garagedoor a").hover(function(){
	      $(this).parent().stop().animate({backgroundPosition: '(0px -100px)'}, 500);
	}, function() {
	      $(this).parent().stop().animate({backgroundPosition: '(0px 0px)'}, 500);

Then we bind the "hover" event to each of the menu's anchor links. When the hover event occurs over those links, jQuery finds the parent element, and does the background-position animation on that element. In our case, the LI element, with the unique shutters. Using the callback function of the hover event (e.g. when the mouse leaves the area) we animate the shutter back into position.

We are also using jQuery's .stop() function here to prevent animation queue buildup (rapidly mousing on and off of an element will cause the garage door to open and close over and over even while you have moused away). Using .stop() also prevents the animation from completing entirely if moused out before the animation completes. If you are interested in altering this so that the garage door animation happens in its entirety every time, use this plugin.

And there we have it, a nice looking menu with a pretty neat animated effect using jQuery!

View Demo   Download Files

The CSS3 Method

We just covered using jQuery to accomplish the garage door effect. jQuery is a good fit (although nearly every JavaScript library has animation helpers) because it can make the animation work across all browsers. If we were considering this garage door menu a progressive enhancement to our site, we could accomplish the same thing using CSS3, specifically the transition property. Transitions are more than capable of the same simple animations we were using jQuery for.

With the base that we already have from the jQuery method, we can super easily convert it to the CSS3 method.

  1. Remove all the JavaScript
  2. Change the list elements CSS to include the transition property
  3. Add a hover event to change the background-position
#garagedoor li {
  width: 200px;
  height: 100px;
  display: block;
  float: left;
  -webkit-transition: background-position 0.6s ease;
  -moz-transition: background-position 0.6s ease;
  -ms-transition: background-position 0.6s ease;
  -o-transition: background-position 0.6s ease;
  transition: background-position 0.6s ease;

#garagedoor li:hover {
  background-position: 0 -100px !important;

Update: In past versions of this article, I ommitted some transition vendor prefixes. For example, I left out -o-, because the current version of Opera at the time supported transitions but not on the background-position property (weird). I have added it back in because it now works. But the more important message is, I probably should have had it in there in the past because it was clearly just a shortcoming that would be fixed in the future.

More on CSS transitions here.

Combining Both CSS3 and jQuery

The most feel-good way to accomplish a technique like this, in my opinion, is to use CSS3 where supported and fallback to a JavaScript method. The best way to handle this: Modernizer! Modernizr is a small JavaScript library you can include on your pages to help identify what that browser is capable of handling.

In our case, we need to know if the browser can handle CSS transitions. Modernizr applies a class to the html element on the page called csstransitions if this is possible. So we just change the selector for the CSS transitions specific code:

/* Modernizer Enabled */
.csstransitions #garagedoor li {
  -webkit-transition: background-position 0.6s ease;
  -moz-transition: background-position 0.6s ease;
  -ms-transition: background-position 0.6s ease;
  -o-transition: background-position 0.6s ease;
  transition: background-position 0.6s ease;
.csstransitions #garagedoor li:hover {
  background-position: 0 -100px !important;

This ensures that browsers that don't support the transition won't even attempt it. For those browsers, we'll be doing a jQuery-based fallback. You may already be using jQuery on your page for other reasons. In our case, we are not, so let's say that we only want to load jQuery at all if needed for the fallback.

With Modernizr, we'll conditionalize our code:

if (!Modernizr.csstransitions) {
  // do fallback stuff

The trick here is that loading a script within JavaScript is a bit tricky, especially since we can't use jQuery yet. What we'll do is leverage this dynamic loading idea. We will:

  1. Test if jQuery is loaded
  2. If not (won't be on first run)...
  3. - Load the script by writing it to the document
  4. - Go to #1
  5. If jQuery is loaded...
  6. Load the backgroundPosition plugin
  7. Code for doing animation

Here's the load:

var jQueryScriptOutputted = false;

function initJQuery() {
    if (typeof(jQuery) == 'undefined') {
        if (!jQueryScriptOutputted) {
            jQueryScriptOutputted = true;
            // Primitive way of loading scripts (no library yet)
            document.write("<scr" + "ipt src=""></scr" + "ipt>");
        setTimeout("initJQuery()", 50);
    } else {
    	// jQuery way of loading scripts
    	$.getScript('js/jquery.backgroundPosition.js', function() {
            // Set CSS in Firefox (Required to use the backgroundPosition js)
			$('#shutter1').css({backgroundPosition: '0px 0px'});
			$('#shutter2').css({backgroundPosition: '0px 0px'});
			$('#shutter3').css({backgroundPosition: '0px 0px'});
			$('#shutter4').css({backgroundPosition: '0px 0px'});

			// Animate the Shutter  
			$("#garagedoor a").hover(function() {	
			      $(this).parent().stop().animate({backgroundPosition: '(0px -100px)'}, 500);
			    }, function() {
			      $(this).parent().stop().animate({backgroundPosition: '(0px 0px)'}, 500);


if (!Modernizr.csstransitions) {


You know the drill people. Do whatever you want with this, preferably use it in a big corporate project with no credit and get rich.

View Demo   Download Files


  1. This is very cool, I will definitely need to keep this and use it somewhere!

  2. Oops! On IE7 only works the first door!

  3. Permalink to comment#

    Really nice effect, but Josep Viciana is right in IE only the first door works.

  4. Yup, extremely cool, but as others have said IE7 barfs on anything other than the first door.

    Line 23, char 16, ‘undefined’ is null or not an object (happens when you hover over the second or subsequent doors)

    It is obviously scared of the snake :-)

  5. Extremely cool effect, but like Josep says it has flaw.. it also only shows ‘what’s behind door # 1′ in FF2

  6. Only opens the first door in FF2 and MSIE7 on XP Pro SP3.

  7. dangdang
    Permalink to comment#

    Funny behavior in FF3. The “Link1″ “Link2″ etc. text links still show up and the doors only open when you hover over the text links not the entire block?

  8. This problem in IE 7 and FF2 should be fixed.

  9. dangdang
    Permalink to comment#

    Yep! Works great now on XP-SP3 FF3! This is awesome! I will be using it soon. Thanks!

  10. Permalink to comment#

    Hey Chris, did you get dugg (digg’d)? Been over half an hour trying to read this article. Glad I finally made it.

  11. Permalink to comment#

    I move my mouse over and out of the pictures 5 times, and they still animates although i’ve move my mouse out :D

  12. anonymous
    Permalink to comment#

    yeah, there seems to be a bug .. you didn’t ignore the mouse event if you are already in the process of opening/closing the garage door.

    Just move your mouse over the door 10 times very quickly and then move it out….

  13. Can’t see what all the fuss is about. It is a great bit of coding, and it works absolutely fine in Firefox 3.0.1, Opera 9.27, Safari for Windows 3.1.2 (525.21). Maxthon 2.1, and IE7 7.6.6006.18000 all on Windows Vista.

  14. yuki
    Permalink to comment#

    this was a css ah-ha moment, thanks.

  15. cool technique, working fine in mozilla

  16. bellissimo

  17. thomas peklak
    Permalink to comment#

    Cool stuff!!!
    Small enhancement: you could stop the animation when the mouse leaves, if it is still active.

  18. You are one of my favorite!

    This is the coolest menu I’ve ever seen in my short life. I have been looking for a menu in which the hover image moves with the mouse when navigate through the menu. Have you seen that one?

  19. Chris, I would suggest putting .stop() in there like:


  20. @Benjamin: Ah ha, very nice. The live example has been updated and it works much nicer now. Helpful suggestions are always nicer than cries of “it’s broken!” =)

  21. Jarod
    Permalink to comment#

    What an awesome tutorial. This is my first time responding to a tutorial. I was impressed. Then again, I’ve been really impressed with jquery lately. Great tutorial. I’ve subscribed.



  22. Permalink to comment#

    Nice Job Chris!!

    You finally got me to say: nice, I have been waiting for one of yours to impress! Great work, nice effect, well planned, well documented, from one designer/developer to another.. pat yourself on the back.. best one yet! Keep them coming, I only hope to follow your lead and actually start using my blog.

    Nice comments box too! Glad I finally used it!

  23. Really nice effect! I love JQuery, so simple to get something which looks as good as something done in flash

  24. ty
    Permalink to comment#

    I really love the menu.
    In my debugging install of IE6 all that is seen is light blue background color rounded corner boxes (perhaps because they are png images). And on mouseover a quick flash of the background, probably a hover glitch?
    Great technique, and as a plugin with the bugs worked out would be just killer.

  25. Sick and slick. Nice work once again.

  26. Chris, If you can working in the bounce effect, that would really make it pop.

  27. I hate to quote you here, but….didn’t I request an ass shot?

  28. great stuff!!, cross browser also :D

  29. Very ingenious. Would you create vertical one?

  30. Permalink to comment#

    Thanks for this Chris, it will be incorporated into my blog re-design as a way to show off my latest work.

    Thanks again!

  31. Harry Mannemela
    Permalink to comment#


    I have downloaded the files and when I opened the page, I am not getting any slides or so in IE6 (XP).

    It works fine in Mozilla thou.
    Could someone help me to tweak it so that it works in IE6 and IE7?

    Thanks in advance,

  32. Alper
    Permalink to comment#

    hey but it’s not work on IE6??

  33. elvisparsley
    Permalink to comment#

    This is great, but what a shame that it does not work in ** IE6.
    Can anyone work it out please?

  34. Permalink to comment#

    And where script updates for IE6????

  35. Luc
    Permalink to comment#

    Anyone found a solution for the error with IE?

    Line 23 char 16 – Undefined bla bla bla….

    because i need 8 boxes… any help would be much appreciated

    All other browsers work well…. but not IE… please help help help….

  36. I really think that IE6 is now rather outdated, and visitors to this page who complain that the routine does not work should really update to the latest version of IE from the Microsoft web site.

    It would then save lots of moans and groans.

    Personally I have found that the routine works in ALL of the most used current version browsers.

  37. Luc
    Permalink to comment#

    Gordon Tatler – not sure if you are referring to my post but i’m talking about IE7

    Are you able to have 8 boxes and they all work well?

    4 I’m ok…. 8, not…. any idea or solution to suggest?

  38. elvisparsley
    Permalink to comment#

    Gordon, I assume you are not a web developer. Unfortunately there are many people out there who are using IE6. When we make a website, we have to accomodate them as well. So you are completely missing the point.

    • I am a web developer and we have completely abandoned IE6. We put a sniffer on there that says if you are using IE6 that you need to upgrade. It is 2 versions behind now. I personally think its time to upgrade (or better yet, switch from IE altogether) as you are missing out on a lot of really great stuff. IMHO

    • oh der. Just saw his comment was from ’08. Ha ha. oops. I do hope you have moved on by now!

  39. ElvisParsley: No, I am not a web developer, and as such may not be fully aware of all the niceties of web development and backward compatibility.

    However, until recent retirement I was a network administrator with over 100 computers under my control. Whenever new operating systems, applications or browsers were released I always thoroughly tested them and then, provided they passed my testing and were necessary to the function of the network, I would fully deploy them. So, all of my computers were kept up to date with the latest technology.

    I believe that the Microsoft update page should now automatically update IE to version 7 – most probably version 8 later this year, so the question I ask is why there should be so many “out there” still using IE6 ? Are they not updating their computers regularly (they really should be doing so) ? Or is this a perceived problem only – I ask as my own web statistics seem to indicate the rapid downturn in IE6 visitors to an almost negligible number, IE7, Firefox and Opera taking the top 3 positions.

    So the question I am interested in is :- how far should backward compatibility be taken ? Why stop at IE6 ? How about IE 5.5, IE5, IE4 …….. ? There has to be a stopping point somewhere. Even Microsoft eventually give up !

    Comments ?

    Oh, and by the way. Anyone tried out the new Google Chrome browser yet ? It’s available at and this menu also works in that.

  40. Robert
    Permalink to comment#

    Anyone know what I need to change on this to make it run as a php file? In other words, if I rename the .html file to .php what do I need to change for it to work? Because that change has broken mine :)

  41. To fix the only one window openning problem,on the jquery that you copy from this site, after the;

    $(‘#shutter1′).css({backgroundPosition: ‘0px 0px’});


    $(‘#shutter2′).css({backgroundPosition: ‘0px 0px’});
    $(‘#shutter3′).css({backgroundPosition: ‘0px 0px’}); $(‘#shutter4′).css({backgroundPosition: ‘0px 0px’});

    All your windows will open, I hope that helps, great menu by the way.

  42. buckmajor
    Permalink to comment#

    Hey everyone

    Im newbie here, just wanted to say how impress I am with this website and the techniques used in css which amazes me the most.

    Awesome stuff man, hope to reach that kind of level one day lol.

    CHEERS :)

  43. sfdude
    Permalink to comment#


    DEMO works great under FF3,
    but not at all in IE6 (under XP sp2).
    It just shows 4 empty boxes.

    Developers know better and use IE7, but
    many thousands of users still use IE6…

    Any way a fix can be found for IE6?
    HELP! Anybody take up the challenge?

  44. I noticed that if you downloaded the files from the top of the page instead of at the bottom that the fixes discussed in the comments are not fixed. Namely the “only the first tab works in IE”.

    To fix this change:




    This way the style is applied to all the shutters by class instead of a single shutter by id.

    The other problem of not seeing the shutters or BG image in IE6 is a PNG transparency issue. I found that this little bugger did the trick for me:

    Hope that helps some people utilize this great example. Thanks a lot for the tutorial. I may be using this on Edinboro’s Site:

  45. It seems the text-indent used to hide the link text breaks the link from working in IE6. I am trying to figure out a way to fix this. My initial thought was to replace the text with a transparent gif, but I really like how the menu degrades so that if someone is using a screen reader they still just see it as a list. I suppose I could use alt text on the transparent gif, but not as nice.

    Anyone found a fix for this, that’s a little better than that?

  46. abhishek bhatia
    Permalink to comment#

    hi! I loved your menu. I would want to include a function that is triggered on an onclick event, such that the garage door for the link that I clicked on remains open and rest all remain closed. When you click on any other door, that will remain open leading to closure of the first door. That would be pretty cool. Can you suggest how could I achieve that?? or can you incorporate the changes.

  47. This is a brilliant effect. I will need to use this in future. Thank you

  48. Jake
    Permalink to comment#

    Hi Chris,
    1st wanted to say how much inspiration I get from your site!!!
    I did want to let others know (as to save a couple hours time) that the link to the jquery.backgroundPosition.js (at top) is a bit dated. It should be known that by using the code from that link will cause animation problems (could be my styling though). Best option is to go to "demo" and use "firebug" to view and copy code from jquery.backgroundPosition.js.
    Again Chris, much respect!

  49. Nicola
    Permalink to comment#

    Hi, I try the script into a tag div but doesn’ t work if div is avowed in the css script without any attribute. This problem is verify with FireFox while with IE 7 works without any problem.
    Background image results translante for any pixel on the left board.
    Any suggestion?

  50. Noel
    Permalink to comment#

    Hi Chris,

    Amazing effect. Well done.

    I am new to CSS and jQuery and I have it working on IE, Safari & Chrome. Looks OK in FF aswell until I click on a link and then the background image re-appears. Any ideas what I am doing wrong?

    Can be seen at

  51. I like this, it’s also a nice article Chris. Only one thing bothers me, I know you are able to do this with CSS3 (still not cross-browser compatible) but why would we want to do it in CSS? It looks way smoother with jQuer (Javascript). I just don’t get it, or is it for learning purposes only?

  52. Hey Chris, this doesn’t seem to work on Chrome 5.0.375.127

    • I’m not even sure how to test for that, since Chrome auto updates itself. Chrome is up to version 7 stable and 8 or 9 in dev, so I’m not super worried about that. You may have tried it during a brief second I broke it as well…

    • Yeah may be.. But the positive out of this, I discovered my Chrome was not updating itself and I was in the Stone Chrome age. :P So this pointed out that I need to update it haha. Thanks for that.

  53. Permalink to comment#

    Very nice idea and application of CSS and jQuery, but in my browser (Firefox 3.6.12), I’ve noticed it relies on the jQuery fallback, and I noticed two things about the page functionality:

    1) The left-most “garage door” functioned much more smoothly than the right-most one, and I noticed gradual decreases in the smoothness in the transition. Is there some reason for this?

    2) Side note: View source button does not seem to work AT ALL – brings up a blank black box, with the option to close it, but no source is shown.

    • 1) Seems smooth to me, but animations like this can be real CPU and memory hogs in my experience. Might want to check if closing other applications or restarting your browser helps.

      2) Not sure what’s up with Fx 3.6 and the view source. It’s not vital though, that’s just a fun little add-on for demo pages. In fact I put the word “fancy” there imply that it’s a progressive feature. If you need the source, check out the article above for code samples, or download the whole package.

  54. Permalink to comment#

    Great work.Thanks for sharing.

  55. Permalink to comment#

    Works neither in Safari 5, nor in Chrome 8dev on Win XP.

    • Works in both Safari 5 and Chrome 8 dev on a mac… Don’t know what to tell ya there, I really doubt platform has anything to do with it. Perhaps you have JavaScript turned off?

  56. Great tutorial thanks for sharing Chris!

  57. Permalink to comment#

    Thanks for sharing these examples!

  58. Permalink to comment#

    yeah chris this is absolutely awesome!

    absolutely digging this. i love your thorough explanation and your humour as well.

    definitely wanna use this soon for a site. you are a dude and you rock out with your cock out to tha max.


  59. santosh
    Permalink to comment#

    This effect is not limited to menu only, we already used same effect on our portfolio page here

  60. Permalink to comment#

    This is cool! I can’t believe I came up with this! ;)

  61. Great example. I’d just found Modernizr and was looking for an example to show how it works. Nice one.

    Hasn’t IE6 just passed the 10 year mark when microsoft themselves stop supporting it?

    That said it’s a constant tension: at what point does backwards compatibility hobble the features of a shiny new site for relatively little reward.

    As always graceful degradation should be the answer. I’m sure with a little fiddling it would be possible to degrade to a simple hover state for IE6 or below.

  62. Thanks for this man , I will try to incorporate on my latest blog development work.

  63. Thanks–especially for the explanation of Modernizr! I’ve been wondering about how to best utilize that script.

  64. Permalink to comment#

    What a cool little feature. Much better with the incorporated CSS3. Shame about the Opera problem though

  65. Really enjoy the CSS3 and Modernizr method, Thank you, and not sure if this is the 1st integration of the fancy view source, but nice. LT

  66. Really nice, im always worried about these type of ‘effects’ though as i just know clients will find some archaic machine with Netscape 4 on and it wont work!

  67. O'Ryan
    Permalink to comment#

    Hmm, it seems like the jQuery fallback is a little inconsistent. I’m using Firefox 3.5.13 on XP and the first time I viewed the demo it went to the css3. Firefox 3.5.13 doesn’t support the css3 animations (at least mine didn’t) then I went back a few times via the various links throughout the explanation and it still didn’t work. Then I clicked the last link (not realizing that it was all the same page anyways :P) and the jQuery mode kicked in and it worked great. I refreshed the page and it went back into css3 mode.

  68. Works fine in
    FireFox 3.6.1 2Very nice a smooth. I would not worry about IE6 anymore.

  69. Permalink to comment#


    may i ask you what overflow work for in this script…?

    i think it gives no difference

  70. Cmet
    Permalink to comment#

    @Chris Coyier: jQuery 1.2.6 anyone ? May wanna change that to 1.4.3 or make it /1.4/ or /1/

    • As I said in the post, the background position plugin doesn’t work with 1.4.3 (current at the time of this writing). So, either that needs to be updated or another solution should be found.

  71. lujie
    Permalink to comment#

    Garage Door Style Menu Ie6 no effect

    • Permalink to comment#

      I have modified an earlier version of the sliding door effect that does work under ie6 as well as ff and Chrome. See
      It relies on using quirks mode by not providing a doctype.
      Nasty, I know, but it does work.

  72. janzcindy
    Permalink to comment#

    Hi! really nice tutorial, and easy to understand even though I’m just a beginner :)
    Just wanna know how will I able to center? Because I just needed two menus and it keeps on positioning at the left side. I really don’t know how to make those two menus position at the center.

    Thanks a lot :)

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".