Identify Design
100% Giraffe Approved
Tutorial Preview Avatar

Create a Pure CSS3 Animated Dropdown Menu

Avatar of Woody

by

Tuesday May 15th, 2012 in CSS Tutorials

In our tutorial on Sunday we took a beginner's look at CSS transitions and some animated effects we could achieve with them. We didn't look too much at practical examples though, so in this tutorial we're going to look at how we can use the transition property to create a beautiful and animated drop down menu using pure CSS3.

The best part about using transitions on menus is the menu will retain complete functionality in browsers that do not support the transition property. Normally when we use fancy CSS3 that isn't widely supported we have to take time to ensure it degrades well so that users who use old browsers still have the core functionality of our page. If a user doesn't have transition support built into their browser they will still have the functionality of any effects that are applied just without the animation. This means if we build a fancy animated menu using just CSS3 and the transition property we can focus on making it beautiful rather than interchangeable because if the user doesn't support transitions they'll still have a menu!

With this in mind let's start making our sparkly animated menu. We're going to create a typical drop down menu using the :hover selector. When the user hovers over one of the parent links a drop down box will appear. You are welcome to change any properties to suit the page you're going to be using the menu on to save you a little time.

<div id="example1">

<div class="parent"><a href="#" class="button">Menu One</a>
<div class="sub" id="one">
<a href="/page/">A Link</a>
<a href="/page/">Another Link</a>
<a href="/page/">A Third Link</a>
</div>
</div>

<div class="parent"><a href="#" class="button">Menu Two</a>
<div class="sub" id="two">
<a href="#">More Links</a>
<a href="#">Yet Another Link</a>
<a href="#">A Final Link</a>
</div>
</div>

<div class="parent"><a href="#" class="button">Images Too!</a>
<div class="sub" id="three">
<img src="http://images.identifydesign.net/bird_in_snow.jpg" alt="Bird in Snow">
</div>
</div>

</div>

You will notice in the structure above that I have placed a separate link inside the menus. These links will be the clickable functional links of the parent wrappers. In HTML5 putting links within links causes big problems. The second links won't become visible since they belong within another link and it will also invalidate your source. Bear this in mind when constructing your menu. To fix this problem we'll simply absolutely position this link above the wrapper. Because it's inside the wrapper in the source hovering over the link will still produce the hover effects.

We'll need to add some CSS to the above. We're going to make the links appear when the user hovers over their corresponding parent link and then apply some transitions to make it flashy! You can change all the values below to suit the needs of whatever page

<style type="text/css">

#example1{

width:600px;
height:50px;
background:#000;

}

.parent{

position:relative;
display:block;
width:200px;
height:50px;
float:left;

}

.buttons{

float:left;
display:block;
text-align:center;
width:200px;
height:50px;
line-height:50px;
background:#e5e5e5;

}

.sub{

visibility:hidden; /* This hides the menu until we hover */
position:absolute;
top:50px;
left:0;
width:200px;
height:150px;
border-bottom-left-radius:10px;
border-bottom-right-radius:10px;
overflow:hidden;

}

.parent:hover .sub{

visibility:visible; /* This makes the menu visible when user hovers */
text-align:center;

}

.sub a{

color:#000;
background:#ffc34c;
display:block;
width:200px;
height:50px;
text-align:center;
line-height:50px;

}

.sub a:hover{

background:#f06000;
color:#fff;

}

</style>

So our mark-up combined with the above stylesheets produces the following simple drop down menu:

This menu is now functional, but we haven't added any animations yet. This is the fun part because it's time to be creative. How would you like your menu to behave? Do you want it to float in from different directions? Change colour? Change opacity? We're going to add three effects to our example menu. On the first link we're going to add an opacity effect, on the second a drop down effect and on the third a zoom effect - and of course we'll show you how to do it.

If you're unfamiliar with the transition property now would be a good time to familiarise yourself with it. Our tutorial: Welcome to CSS3 Transitions is a detailed look into transitions and how they work and our CSS3 Glossary: Transition entry has more information and examples. It's important you understand how transitions work because this tutorial won't be explaining that; we'll just be using them.

Make the Links Fade In

You have probably seen a fade effect somewhere on a menu before. Chances are it was made with either jQuery or Flash. The same results can be achieved using just CSS3 thanks to transition. All of the effects on this page will be made with just CSS3. As the classes are placed inside the stylesheet that loads on every page and is probably cached, you're saving on HTTP requests already from not needing to include additional scripts or files. You're also reaching a broader audience because CSS can't be blocked, like jQuery sometimes can by plugins. There's also some users who disable Javascript; CSS gets around this too.

We will declare the stylesheet for #one and add an opacity transition to it. To do this we set the original opacity to 0, the opacity when the user hovers over the parent to 1 and then add an opacity transition to the original class. We are going to make the transition smooth by adding the ease-in-out timing function. This makes the transition start slowly and finish slowly.

In order for this transition to work we'll need to replace the original visibility declaration else the hover off animation will not display. The menu will not be visible anyway because we're lowering it's opacity to zero.

#one{

visibility:visible!important;
opacity:0;
transition:opacity 0.4s ease-in-out;
-moz-transition:opacity 0.4s ease-in-out;
-webkit-transition:opacity 0.4s ease-in-out;
-o-transition:opacity 0.4s ease-in-out;

}

.parent:hover #one{

opacity:1;

}

Now we are going to...

Make the Links Slide In

There's two ways of doing this and it depends entirely on the setup of your page how you go about it. Since we can't hide overflow because the drop down menus wouldn't appear, we have to be mindful of how this is achieved. In the event your menu is being placed directly at the top of an element that you could hide the overflow on, or it's appearing on one of the borders of the page then you can slide the menu in using a left, top, and so forth, transition.

However if like our example boxes the effect is in the middle of content with no visible overflow nearby this won't work because the menu will appear and slide from above, to the left of, so forth, of the original links. This won't do! Want an example? Of course you do.

... Not so great, huh?

The solution is to use height to our advantage. If we set the original height of this box to zero and then change it with a transition it will give the effect of the box sliding from the top and without the overflow issue. This is the method we are going to use because it saves lots of time writing additional mark-up and it still looks nifty.

#two{

visibility:visible!important;
height:0;
transition:height 0.4s ease-in-out;
-moz-transition:height 0.4s ease-in-out;
-webkit-transition:height 0.4s ease-in-out;
-o-transition:height 0.4s ease-in-out;

}

.parent:hover #two{

height:150px;

}

Notice we've replaced the visibility for this menu. Most of the time you won't need to do this but it just happens in these two examples you do! It's a good habit to be in of hiding the content until it's called as it makes sure you don't get any ugly failures in the event something goes wrong.

And for our image we're going to...

Make the Menu Zoom

If you have an image you'd like to place in a frequently accessed part of your page, like an affiliation or advertising image, then placing it in the menu is a good way to go. The problem is it might be out of place without applying some styles to it. This is where our drop down menu comes in useful. The image will be hidden until the user actively hovers over its parent link, which they'll do because the text caught their interest.

But adding a snazzy effect to that image can't hurt, right? Of course not!

We're going to add a transition to the third and final menu box that will make the image zoom into focus sharply and crisply. To do this we'll need to add four transitions: height, width, top and left. We'll also need to do some basic maths for the best effect.

In our example the image is 100 x 100 pixels. The container around it is 200 x 150. This means we have to adjust the position when the third menu is hovered over to create a smooth and crisp zoom effect. We'll set the image to 300x300 and when the user hovers its parent we'll restore it to its original size. Our original wrapper is 150 high, which means we'll need to position the image half of the wrapper minus our zoomed high to the top: in this case, 300-150/2 = 75 pixels.

Repeat the maths with the left which will be 300-200/2 = 50 pixels. So position the top at -75 pixels and the left at -50 pixels:

#three img{

position:absolute;
width:300px;
height:300px;
left:-50px;
top:-75px;
transition:height 0.2s,width 0.2s,left 0.2s,top 0.2s ease-in-out;
-moz-transition:height 0.2s,width 0.2s,left 0.2s,top 0.2s ease-in-out;
-webkit-transition:height 0.2s,width 0.2s,left 0.2s,top 0.2s ease-in-out;
-o-transition:height 0.2s,width 0.2s,left 0.2s,top 0.2s ease-in-out;

}

.parent:hover #three img{

width:100px;
height:100px;
left:0;
top:0;

}

Pretty cool, huh? And there you have an animated menu using nothing but CSS3! The limitations are simply your imagination. You can create some really imaginative effects combining transition. In our last example below we're going to take advantage of transition-delay to create some timed drop down effects.

Adding Timing

You can create delays using transition-delay that will add pauses, breaks or times to transition effects and produce even better animations. Let's use our second example from above as our subject in this example. What if we wanted to make the links appear only once the drop down box had fully appeared? This is relatively simple to do. We'll use our original transition values from the second drop down menu but also add a transition on the links! That's right - transitions can be used inside transition effects. You can see where this is going... Throw in some transition-delay and you'll get staggered animations like this one. Notice I've added a line to change the background of the wrapper to the background of the links. Otherwise we wouldn't see the wrapper expand!

#two{

background:#ffc34c;
visibility:visible!important;
height:0;
transition:height 0.4s ease-in-out;
-moz-transition:height 0.4s ease-in-out;
-webkit-transition:height 0.4s ease-in-out;
-o-transition:height 0.4s ease-in-out;

}

.parent:hover #two{

height:150px;

}

#two a{

opacity:0;
transition:opacity 0.4s ease-in-out;
-moz-transition:opacity 0.4s ease-in-out;
-webkit-transition:opacity 0.4s ease-in-out;
-o-transition:opacity 0.4s ease-in-out;
transition-delay:0.4s;
-moz-transition-delay:0.4s;
-webkit-transition-delay:0.4s;
-o-transition-delay:0.4s;

}

.parent:hover #two a{

opacity:1;

}

So you can combine these delays with a plethora of properties to create some stunning menus. That's the end of our tutorial and examples though I'm afraid. Hopefully this tutorial has given you an insight into how you can combine various transition effects with interfaces to make smooth and animated menus - all with pure CSS3. If you have a page you've made that you'd like us to link to that demonstrates excellent use of transitions in a menu please leave the link in the comments below for everyone to see!

Here's a copy of the combined source with all transitions:

<style type="text/css">

#example1{

width:600px;
height:50px;
background:#000;

}

.parent{

position:relative;
display:block;
width:200px;
height:50px;
float:left;

}

.buttons{

float:left;
display:block;
text-align:center;
width:200px;
height:50px;
line-height:50px;
background:#e5e5e5;

}

.sub{

visibility:hidden; /* This hides the menu until we hover */
position:absolute;
top:50px;
left:0;
width:200px;
height:150px;
border-bottom-left-radius:10px;
border-bottom-right-radius:10px;
overflow:hidden;

}

.parent:hover .sub{

visibility:visible; /* This makes the menu visible when user hovers */
text-align:center;

}

.sub a{

color:#000;
background:#ffc34c;
display:block;
width:200px;
height:50px;
text-align:center;
line-height:50px;

}

.sub a:hover{

background:#f06000;
color:#fff;

}

/* Drop Down One: Opacity */

#one{

visibility:visible!important;
opacity:0;
transition:opacity 0.4s ease-in-out;
-moz-transition:opacity 0.4s ease-in-out;
-webkit-transition:opacity 0.4s ease-in-out;
-o-transition:opacity 0.4s ease-in-out;

}

.parent:hover #one{

opacity:1;

}

/* Drop Down Two: Slider */

#two{

visibility:visible!important;
height:0;
transition:height 0.4s ease-in-out;
-moz-transition:height 0.4s ease-in-out;
-webkit-transition:height 0.4s ease-in-out;
-o-transition:height 0.4s ease-in-out;

}

.parent:hover #two{

height:150px;

}

/* Drop Down Three: Zoom */

#three img{

position:absolute;
width:300px;
height:300px;
left:-50px;
top:-75px;
transition:height 0.2s,width 0.2s,left 0.2s,top 0.2s ease-in-out;
-moz-transition:height 0.2s,width 0.2s,left 0.2s,top 0.2s ease-in-out;
-webkit-transition:height 0.2s,width 0.2s,left 0.2s,top 0.2s ease-in-out;
-o-transition:height 0.2s,width 0.2s,left 0.2s,top 0.2s ease-in-out;

}

.parent:hover #three img{

width:100px;
height:100px;
left:0;
top:0;

}

/* Drop Down Two: Slider with Delay */

/* Uncomment this block to add the delay on the links

#two{

background:#ffc34c;
visibility:visible!important;
height:0;
transition:height 0.4s ease-in-out;
-moz-transition:height 0.4s ease-in-out;
-webkit-transition:height 0.4s ease-in-out;
-o-transition:height 0.4s ease-in-out;

}

.parent:hover #two{

height:150px;

}

#two a{

opacity:0;
transition:opacity 0.4s ease-in-out;
-moz-transition:opacity 0.4s ease-in-out;
-webkit-transition:opacity 0.4s ease-in-out;
-o-transition:opacity 0.4s ease-in-out;
transition-delay:0.4s;
-moz-transition-delay:0.4s;
-webkit-transition-delay:0.4s;
-o-transition-delay:0.4s;

}

.parent:hover #two a{

opacity:1;

}

Remove this and the opening comment to add the delay!*/

</style>

<div id="example1">

<div class="parent"><a href="#" class="button">Menu One</a>
<div class="sub" id="one">
<a href="/page/">A Link</a>
<a href="/page/">Another Link</a>
<a href="/page/">A Third Link</a>
</div>
</div>

<div class="parent"><a href="#" class="button">Menu Two</a>
<div class="sub" id="two">
<a href="#">More Links</a>
<a href="#">Yet Another Link</a>
<a href="#">A Final Link</a>
</div>
</div>

<div class="parent"><a href="#" class="button">Images Too!</a>
<div class="sub" id="three">
<img src="http://images.identifydesign.net/bird_in_snow.jpg" alt="Bird in Snow">
</div>
</div>

</div>

Leave a reply

You must be logged in to post a comment.