Mega menus, which are alternatively called multi-level, fly-out, or tiered menus, are an excellent form of website navigation.
These menus—whether arranged horizontally or vertically—allow visitors to quickly and intuitively browse a site's hierarchy, which is of particular importance on ecommerce sites.
Frequently, mega menus are executed using either JavaScript or Flash and ActionScript. While these are both excellent choices, there may be certain times or certain projects wherein a lighter, all CSS solution, is called for. So in this quick tutorial, I will describe one approach to building a pure-CSS mega menu.
Building the HTML
For this tutorial, I set up a simple page that has a header and a short, four-anchor menu.

Within my HTML, I need to construct the mega menu as a series of nested unordered lists. Take a look at the completed HTML. Below, I will describe one of the individual sections of the mega menu in some detail.
<!doctype html> <html lang="en"> <head> <title>Pure CSS Mega Menu</title> <meta charset="utf-8"> <link type="text/css" rel="stylesheet" href="style.css"> <link rel="icon" type="image/png" href="favicon.png"> </head> <h1 class="header">Pure CSS Mega Menu</h1> <ul class="navigation"> <li class="level1"> <a href="">Featured</a> <ul class="level2" id="nav-featured"> <li><object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/AFJEw4hB7i4?fs=1&hl=en_US&hd=1&color1=0x3a3a3a&color2=0x999999"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/AFJEw4hB7i4?fs=1&hl=en_US&hd=1&color1=0x3a3a3a&color2=0x999999" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object></li> </ul> </li> <li class="level1"> <a href="">Reviews</a> <ul class="level2" id="nav-reviews"> <li><a href="http://www.pluggedin.com/movies/intheaters/megamind.aspx">Megamind</a></li> <li><a href="http://www.pluggedin.com/movies/intheaters/theamerican.aspx">The American</a></li> </ul> </li> <li class="level1"> <a href="">Trailers</a> <ul class="level2" id="nav-trailers"> <li><object width="200" height="137"><param name="movie" value="http://www.youtube.com/v/mnoW5-DmIUM?fs=1&hl=en_US&hd=1&color1=0x3a3a3a&color2=0x999999"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/mnoW5-DmIUM?fs=1&hl=en_US&hd=1&color1=0x3a3a3a&color2=0x999999" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="200" height="137"></embed></object></li> <li><object width="200" height="137"><param name="movie" value="http://www.youtube.com/v/tav42JTdW4A?fs=1&hl=en_US&hd=1&color1=0x3a3a3a&color2=0x999999"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/tav42JTdW4A?fs=1&hl=en_US&hd=1&color1=0x3a3a3a&color2=0x999999" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="200" height="137"></embed></object></li> <li><object width="200" height="137"><param name="movie" value="http://www.youtube.com/v/yJtot_f-snU?fs=1&hl=en_US&hd=1&color1=0x3a3a3a&color2=0x999999"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/yJtot_f-snU?fs=1&hl=en_US&hd=1&color1=0x3a3a3a&color2=0x999999" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="200" height="137"></embed></object></li> </ul> </li> <li class="level1"> <a href="">Clips</a> <ul class="level2" id="nav-clips"> <li>One</li> <li>Two</li> </ul> </li> </ul> </body> </html>
As you can see, the mega menu is organized as an unordered list. That ul has a class name of "navigation."
<ul class="navigation">
Each list item in the "navigation" list has a class name of "level1", signifying that it is the first level of the mega menu.
As an aside, some developers use the class name "level0" for the anchor level in a mega menu. However, I start with "1." Of course, you can name the list item's class anything you want, but in more complicated (multi-tiered) menus, a naming convention that helps describe the list item's relationship to the anchor is extremely useful.
<li class="level1">
Each "level1" or anchor level list item has two child elements: an anchor and a nested unordered list.
<li class="level1"> <a href="">Clips</a> <ul class="level2" id="nav-clips"> <li>One</li> <li>Two</li> </ul> </li>
The anchor is, as you can imagine, what the user will see when the page loads and until the user hovers over the menu. The nested unordered list contains the content that will be displayed when the user hovers. This list has a class name of "level2" and a unique id .
It is worth mentioning that just about any element from a div to a paragraph would have worked in the place of my unordered list. But I have found that when a server side script generates these menus dynamically, it may be easier to use the same basic structure for each section of the mega menu. Thus I tend to use the nested unordered lists, which work fine for a series of links or a series of videos.
CSS Display and Position
Now I am going to create the required CSS declarations. There are two key features I need to focus on: (1) the display attribute for the "level2" list, and (2) that list's position relative to the rest of the page.
Setting the nested list's display to "none" hides the menu's additional content.
.navigation .level1 .level2 {display: none; }
Next, I set the "level2" list's position to "absolute" and the main "navigation" list's position to "relative."
.navigation { position: relative;}
.navigation .level1 .level2 {display: none; position: absolute;}
As you may know, when an element is given an "absolute" position, it is taken outside of the page flow. If the "level2" section of the mega menu did not have an absolute position, it would change the entire page layout when it appeared. But the "absolute" positioning allows it to pop in place without affecting any other elements.
Normally, an absolutely position element will be placed in the upper left corner of the page at the (0,0) coordinates. But I want the "level2" list to appear directly below the anchor. So I give the parent, "navigation" unordered list a "relative" position, which sets the absolutely positioned second-tier list inside of the "navigation" list.
The CSS :hover Pseudo-Class
Now I need to make the "level2" content appear when a user hovers over an anchor. The secret to getting this to work is to use the CSS :hover pseudo-class.
Most developers are familiar with using this pseudo-class to underline a link or change an item's background, without realizing that the pseudo-class can be used anywhere in the style declaration.
Take a quick look at the style declaration for the "level2" list.
.navigation .level1 .level2 {display: none; position: absolute;}
Now take a look at this declaration using the :hover pseudo-class.
.navigation .level1:hover .level2 {display: block;}
The :hover is placed on the "level1" list item. But it affects the style for the "level2" item. When a user hovers over the anchor, which is contained within the "level1" list, the "level2" content's display attribute is changed to "block."
Finally, I dress up the mega menu's appearance, adding, for example, different width styles to each section of the menu, background colors, and padding.
body {margin: 50px auto; width: 1000px; background: #ececec;}
.navigation {list-style:none; margin: 40px 0 0; padding:0; position: relative;}
.navigation .level1 {display: block; float: left;}
.navigation .level1:hover a {background: #808080; color: #000;}
.navigation .level1 a {padding: 20px; color: #fff; text-transform: uppercase; text-decoration: none; font-weight: bold; background: #C22803;}
.navigation .level1 .level2 {display: none; position: absolute; top: 40px; padding: 20px 10px 10px 20px; list-style: none;}
.navigation .level1:hover .level2 {display: block; z-index: 99; background: #808080;}
#nav-featured {width: 660px;}
#nav-reviews {width: 150px; padding: 20px 0;}
#nav-reviews a {padding: none; color: #000; text-transform: none; text-decoration: none; font-weight: bold; background: none;}
#nav-trailers {width: 220px;}
#nav-clips {width: 55px;}
Summing Up
I have demonstrated how to build a pure CSS mega menu. This menu is capable of hiding and revealing any sort of content you can imagine.
Related Articles
- CSS Media Queries For Mobile Designs
- CSS3's Box-Shadow Adds Drop Shadows, Inner Shadows
- Three Techniques for Cross-Browser CSS Gradients
