Build a Pure CSS Animated Slide-In Dropdown Nav Menu
This page may contain links from our sponsors. Here’s how we make money.
Pure CSS is more than enough to create incredible web animations. These can range from sliders to carousels and even dropdown navigation menus.
But the trickiest part about CSS animation is learning how it all works. In this tutorial, I’ll guide you through the process of building a slide-in dropdown navigation menu from very simple code. The nav submenu links will slide in from the right-hand side of the screen and disappear when hidden.
Take a look at the live demo below to see how this works in your browser.
Building the HTML
I’ve re-built an effect from CodePen originally made by Andreas Eracleous. I’ve redesigned the nav bar to not only be larger and fullscreen but to also stay fixed while scrolling down the page.
Let’s start with the raw HTML and work our way to the animations
First I’m creating a very basic HTML5 doctype. In the head section, I’ll add a link to my own stylesheet named styles.css, along with a CDN-hosted link to Normalize.css. This just makes the design a lot easier to manage without re-writing lines of code.
<!doctype html> <html lang="en-US"> <head> <meta charset="utf-8"> <meta http-equiv="Content-Type" content="text/html"> <title>CSS Animated Dropdown Slide-In Menu Demo</title> <link rel="shortcut icon" href="https://www.vandelaydesign.com/wp-content/themes/vd/assets/graphics/favicon.png"> <link rel="icon" href="https://www.vandelaydesign.com/wp-content/themes/vd/assets/graphics/favicon.png"> <link rel="stylesheet" type="text/css" media="all" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.css"> <link rel="stylesheet" type="text/css" media="all" href="styles.css"> </head>
In the body you’ll find some basic HTML5 elements containing a simple unordered list. Each list item contains a link and the dropdown items contain a secondary UL element.
Note the links don’t lead anywhere, but this is easy to change in a real menu. I’ve kept all links hashed to keep visitors on the demo page.
<header class="topbar"> <nav> <ul class="nav"> <li><a href="#">Link 1</a></li> <li> <a href="#">Dropdown 1</a> <ul> <li><a href="#">Category 1</a></li> <li><a href="#">Category 2</a></li> <li><a href="#">Category 3</a></li> <li><a href="#">Category 4</a></li> </ul> </li> <li> <a href="#">Dropdown 2</a> <ul> <li><a href="#">Category 1</a></li> <li><a href="#">Category 2</a></li> <li><a href="#">Category 3</a></li> </ul> </li> <li><a href="#">Link 4</a></li> <li><a href="#">Link 5</a></li> </ul> </nav> </header>
The header element acts as an overall 100% width container. The internal nav element is similar but can be set up with a fixed width to center the content. So if your layout never goes beyond 900px you can set max-width: 900px to the nav element.
For this demo, I’ve expanded the menu to take up the entirety of the window.
Lastly, I have a div with the class .content holding lorem ipsum paragraphs. This does not affect the menu’s operation, but it does showcase the ability to scroll and maintain a fixed menu at the top of the page.
Base CSS Styles
Moving over to my styles.css file is where the real action happens. This code uses natural CSS animation with keyframes and lots of pseudo-classes where appropriate. The syntax is at least intermediate-level CSS but it’s easy to understand with some patience.
@charset 'UTF-8'; @import url('https://fonts.googleapis.com/css?family=Ubuntu:400,700'); body { overflow-x: hidden; background-color: #eee; } p { font-size: 1.2em; line-height: 1.35em; color: #666; font-family: Helvetica, sans-serif; } /** page structure **/ .content { display: block; max-width: 550px; margin: 0 auto; padding: 0 15px; padding-top: 120px; } .topbar { display: block; position:fixed; top: 0; width: 100%; height: 64px; background: #474747; } nav { position: relative; width: 100%; }
First I have all the basic CSS page structure with a UTF-8 charset and the Ubuntu Google Webfont.
You’ll notice that the header with a class .topbar is fixed to the page. This allows the full menu to stay fixed as you scroll down the page.
The next block of code defines how the menu should behave. I’m using ul.nav to identify this one particular unordered list with a class, otherwise, we’d be targeting every unordered list on the page.
/** navigation style **/ ul.nav { display: block; float: left; width: 100%; margin: 0; padding: 0; list-style: none; font-family: 'Ubuntu', Helvetica, sans-serif; font-size: 1.1em; text-transform: uppercase; font-weight: bold; background: #474747; } ul.nav > li { display: block; float: left; line-height: 64px; padding: 0 20px; } ul li a { position: relative; text-decoration: none; color: #999; } ul.nav li > ul { position: absolute; display: none; width: 100%; z-index: 99; } ul.nav li > ul li { position: relative; display: block; float: left; color: #fff; z-index: 999; } ul.nav li > ul li a { color: #eee; display: block; padding: 0 20px; line-height: 70px; } ul.nav li > ul li a:hover { color: #474747; } ul.nav > li:hover > a { color: #ececec; } ul.nav li:hover > ul { display: block; }
Every first-level list item has a line-height of 64px. This is my chosen height for the menu itself – obviously, you can adjust as needed.
The .nav li > ul selector targets the very first unordered list found within a list item. This would contain a secondary menu of links that appear in the dropdown, so it’s hidden by default with absolute positioning.
Since we have these elements positioned we can use the z-index property. This forces all sub-menu list items to stay on top of the unordered list(so links appear on top of the blue background).
Animated Action
In the latter portion of my CSS, you’ll find the animation code. Keep in mind there are two subtle animations: first, the sub-menu drops down into view, then the sub-links slide into view from the right side of the page.
ul.nav li:hover > ul > li { display: block; left: -3%; /* Safari 4+ */ -webkit-animation: nav-anim-left 0.6s; /* Fx 5+ */ -moz-animation: nav-anim-left 0.6s; /* Opera 12+ */ -o-animation: nav-anim-left 0.6s; /* IE 10+, Fx 29+ */ animation: nav-anim-left 0.6s; } ul.nav:first-child li > ul:before { content: " "; position: absolute; width: 100%; height: 70px; left: 50%; background-color: #769cb7; } ul.nav:first-child li > ul:after { content: " "; position: absolute; width: 100%; height: 70px; right: 50%; background-color: #769cb7; } ul.nav:first-child li:hover > ul:before, ul.nav:first-child li:hover > ul:after { -webkit-animation: nav-down 0.25s; /* Fx 5+ */ -moz-animation: nav-down 0.25s; /* Opera 12+ */ -o-animation: nav-down 0.25s; /* IE 10+, Fx 29+ */ animation: nav-down 0.25s; }
Each animation is later defined using keyframes, but you can see they have individual names applied to the appropriate elements. nav-anim-left animates the list items to the left, while nav-down animates the submenu navbar down into view.
One more advanced feature is the use of :before and :after pseudo-classes on the sub-menu list. Both parts comprise a full 100% width block with the same background color. One appears before the links, the other appears after them.
Since the menu is positioned absolute it can’t fit the 100% width by default. So this little trick forces a full-size background onto the element. It also allows the user to hover their mouse across the entire blue bar without auto-closing the submenu.
/** big sub-menu dropdown arrow **/ ul.nav:first-child > li:hover > a:not(:last-child):after { position: absolute; content: " "; width: 0; height: 0; top: 36px; left: 0; right: 0; margin: 0 auto; border-left: 15px solid transparent; border-right: 15px solid transparent; border-top: 15px solid #474747; z-index: 9999; } /** little link arrow **/ ul.nav:first-child > li > a:not(:last-child):after { position: absolute; display: inline-block; content: " "; width: 0; height: 0; top: 50%; margin-left: 2px; vertical-align: middle; border-top: 4px solid; border-right: 4px solid transparent; border-left: 4px solid transparent; }
Another neat CSS effect is the creation of arrow icons. These use the border transformation hack in CSS to create a border that gets cut off by positioning.
The result is a downward-pointing arrow which you’ll notice directly next to dropdown links, and underneath the links when the submenu is open.
/** Dropdown Animation **/ @-webkit-keyframes nav-down { 0% { height: 0px; } 100% { height: 100px; } } @-moz-keyframes nav-down { 0% { height: 0px; } 100% { height: 100px; } } @-o-keyframes nav-down { 0% { height: 0px; } 100% { height: 100px; } } @keyframes nav-down { 0% { height: 0px; } 100% { height: 100px; } } /** Sub-Nav Sliding Animation **/ @-webkit-keyframes nav-anim-left { 0% { left: 100%; } 100% { left: -3%; } } @-moz-keyframes nav-anim-left { 0% { left: 100%; } 100% { left: -3%; } } @-o-keyframes nav-anim-left { 0% { left: 100%; } 100% { left: -3%; } } @keyframes nav-anim-left { 0% { left: 100%; } 100% { left: -3%; } }
And finally, the @keyframe rule is used to define the nav dropdown and link slide effects.
You’ll see that both animations rely on simple CSS properties. At the start of the animation the navbar’s height is 0px, then forced to 100px.
The links are positioned at 0% then moved over to -3%(just outside the dropdown container). You can adjust these values to make the navbar larger, or to animate the links into different locations.
Also, try adjusting the animation properties found earlier in the code to increase or decrease the animation speed.
For more relevant web dev content, please check out:
- Code a Vertical Accordion Nav Menu with jQuery
- Ultimate Guide to HTTP Status Codes and Server Error Messages
- Coding a Bare Bones HTML/CSS Email Newsletter Template
Wrap-Up
I hope this tutorial offers an interesting glimpse into CSS development. With modern CSS animations, you can build practically anything with a high level of accuracy and browser support.
Feel free to download a copy of my source code and play around in your own projects. And if you build anything cool on top of this code feel free to link us in the discussion area.