CSS Lists as Hierarchical Navigation
- To use lists as vertical navigation.
- To use nested lists for multi-level navigation.
- To use lists as horizontal navigation.
- To use lists as drop-down navigation.
Navigation bars or menus present a list of choices to the visitor. For example,
- Home
- Services
- Products
- Support
- Blog
- About
- Contact
Often these choices will have nested options. For example, under About, you might find:
- Company History
- Our Staff
- Press Releases
- Investor Information
In this lesson of the CSS tutorial, you'll learn how to properly mark up these menus using HTML lists and to use CSS to style them.
Menus as Lists
Let's start by marking up the first list shown above as HTML and giving the list an id of "mainMenu":
<ul id="mainMenu"> <li><a href="home.html">Home</a></li> <li><a href="services.html">Services</a></li> <li><a href="products.html">Products</a></li> <li><a href="support.html">Support</a></li> <li><a href="blog.html">Blog</a></li> <li><a href="about.html">About</a></li> <li><a href="contact.html">Contact</a></li> </ul>
With no CSS, this menu will display as follows:
Let's now see how we can turn the list into a stylish navigation menu.
CSS Horizontal Menu
First, we'll create a horizontal menu that looks like this:
We will follow these steps:
-
Remove all the default list styling. We can do this using Eric Meyer's reset CSS, which contains the following rule:
ol, ul { list-style: none; } -
Set the width and margin of the menu. Setting the width prevents the menu from wrapping when the user shrinks the browser window.
#mainMenu { margin:10px; width:900px; font-family: "Trebuchet MS"; } -
Set the list items to display as blocks. We'll also give them a width, float them to the left so that they'll each come up to the right of the preceding item, and give them a margin border.
#mainMenu li { display:block; width:120px; float:left; margin-left:2px; border:1px solid #000; } -
Change the a elements to block-level elements. We'll also add some formatting styles and remove the underline with text-decoration:none.
#mainMenu a { display:block; padding:3px; text-decoration:none; background-color:#fff; color:#009; } - Finally, we change the hover state of the links so that they highlight when a user points to them:
#mainMenu a:hover { background-color:#009; color:#fff; }
That's it. The full CSS code is shown below:
Code Sample: CssListMenus/Demos/CssMenu-horizontal.html
---- Code Omitted ----<link type="text/css" rel="stylesheet" href="../reset-meyer.css" /> <style type="text/css"> #mainMenu { margin:10px; width:900px; font-family: "Trebuchet MS"; } #mainMenu li { display:block; width:120px; float:left; margin-left:2px; border:1px solid #000; } #mainMenu a { display:block; padding:3px; text-decoration:none; background-color:#fff; color:#009; } #mainMenu a:hover { background-color:#009; color:#fff; } </style>---- Code Omitted ----
Open CssListMenus/Demos/CssMenu-horizontal.html in your browser to see it in action.
CSS Vertical Menu
Vertical menus are created in much the same way, but they're even easier. The steps below show how to create a menu that looks like this:
- Remove all the default list styling. Again we use Eric Meyer's reset CSS.
-
Set the width and margin of the menu. This time will make the menu much narrower as we're creating a vertical menu:
#mainMenu { margin:10px; width:120px; font-family: "Trebuchet MS"; } -
Set the list items to display as blocks. We'll also set the border properties adding borders to the left, right and bottom edges and then adding a border to the top of only the first list item. We use the :first-child pseudo-class
(see footnote) to do this.
#mainMenu li { display:block; border:1px solid #000; border-top:0px; } #mainMenu li:first-child { border-top:1px solid #000; } -
Change the a elements to block-level elements. Again, we'll also add formatting styles and remove the underline with text-decoration:none.
#mainMenu a { display:block; padding:3px; text-decoration:none; color:#009; } - Finally, we change the hover state of the links so that they highlight when a user points to them:
#mainMenu a:hover { background-color:#009; color:#fff; }
The full CSS code is shown below:
Code Sample: CssListMenus/Demos/CssMenu-vertical.html
---- Code Omitted ----<link type="text/css" rel="stylesheet" href="../reset-meyer.css" /> <style type="text/css"> #mainMenu { margin:10px; width:120px; font-family: "Trebuchet MS"; } #mainMenu li { display:block; border:1px solid #000; border-top:0px; } #mainMenu li:first-child { border-top:1px solid #000; } #mainMenu a { display:block; padding:3px; text-decoration:none; color:#009; } #mainMenu a:hover { background-color:#009; color:#fff; } </style>---- Code Omitted ----
Open CssListMenus/Demos/CssMenu-vertical.html in your browser to see it in action.
CSS Dynamic Menus
Dynamic menus have long been popular on the web. Until relatively recently, it was necessary to use JavaScript to create these menus. The wider support of the :hover pseudo-class changes that. In this section, we'll show you how to create dynamic menus using pure CSS.
The dynamic menus shown in this lesson will not work in Internet Explorer 6 and earlier. To create expanding menus for IE 6 and earlier, you will most likely (see footnote) have to use JavaScript.
CSS Dropdown Menu
So far, we have only looked at how we can use CSS to change the display of single-level menus. But what happens when we introduce a second level of choices using a nested list. The code sample below shows the same horizontal menu we saw before, but with the addition of a nested list:
Code Sample: CssListMenus/Demos/CssMenu-horizontal-nested.html
---- Code Omitted ----<ul id="mainMenu"> <li><a href="home.html">Home</a></li> <li><a href="services.html">Services</a></li> <li><a href="products.html">Products</a></li> <li><a href="support.html">Support</a></li> <li><a href="blog.html">Blog</a></li> <li><a href="about.html">About</a> <ul> <li><a href="history.html">Company History</a></li> <li><a href="staff.html">Our Staff</a></li> <li><a href="press.html">Press Releases</a></li> <li><a href="investorInfo.html">Investor Information</a></li> </ul> </li> <li><a href="contact.html">Contact</a></li> </ul>---- Code Omitted ----
With this nested list in place and without changing the CSS, this page will display as follows:
![]()
By modifying the CSS, we can hide the submenus until the user hovers over one of the parent menu items. Here are the steps:
-
Set the position of the main menu items to relative. We will need to position the submenus using absolute positioning, but absolutely positioned elements are positioned within their nearest non-statically positioned containing element. So, to prepare for that, we'll first make the main list items relatively positioned:
#mainMenu li { position:relative; /*other declarations omitted*/ } -
Position the submenus absolutely. Submenus are contained in ul elements within li elements. The following rule uses absolute positioning to position them immediately below those li elements: The result:
#mainMenu li ul { position:absolute; margin:0px; padding:0px; left:-3px; top:22px; }
- Hide the submenus. Add display:none; to the rule above to hide the submenus.
-
Style the submenu options. The two rules below add borders around the submenu options. We turn the top border off for all but the first option, which we identify with the :first-class pseudo-class so that we don't get a double-thick border resulting from top and bottom borders of adjacent options.
#mainMenu li ul li { width:150px; font-size:smaller; border-top:none; } #mainMenu li ul li:first-child { border-top:1px solid #000; } -
Display the submenu when the user hovers over the main option. Modern browsers allow the :hover pseudo-class for almost all elements, including list items. The code below sets the display property of the submenu to block when the user hovers over the parent list item:
#mainMenu li:hover ul { display:block; }
That's it. The full CSS code is shown below:
Code Sample: CssListMenus/Demos/CssMenu-dropdown.html
---- Code Omitted ----<link type="text/css" rel="stylesheet" href="../reset-meyer.css" /> <style type="text/css"> #mainMenu { margin:10px; width:900px; font-family: "Trebuchet MS"; } #mainMenu li { position:relative; display:block; width:120px; float:left; margin-left:2px; border:1px solid #000; } #mainMenu a { display:block; padding:3px; text-decoration:none; background-color:#fff; color:#009; } #mainMenu a:hover { background-color:#009; color:#fff; } #mainMenu li ul { position:absolute; margin:0px; padding:0px; left:-3px; top:22px; display:none; } #mainMenu li ul li { width:150px; font-size:smaller; border-top:none; } #mainMenu li ul li:first-child { border-top:1px solid #000; } #mainMenu li:hover ul { display:block; } </style>---- Code Omitted ----
Open CssListMenus/Demos/CssMenu-dropdown.html in your browser to see it in action.
CSS Flyout Menu
Let's now take a look at creating a flyout menu, which is very similar to creating a dropdown menu. The code sample below shows the vertical menu we saw before, but with the addition of several nested lists:
Code Sample: CssListMenus/Demos/CssMenu-vertical-nested.html
---- Code Omitted ----<ul id="mainMenu"> <li><a href="home.html">Home</a></li> <li><a href="services.html">Services</a> <ul> <li><a href="service1.html">Service 1</a></li> <li><a href="service2.html">Service 2</a></li> <li><a href="service3.html">Service 3</a></li> </ul> </li> <li><a href="products.html">Products</a> <ul> <li><a href="product1.html">Product 1</a></li> <li><a href="product2.html">Product 2</a></li> <li><a href="product3.html">Product 3</a></li> </ul> </li> <li><a href="support.html">Support</a></li> <li><a href="blog.html">Blog</a></li> <li><a href="about.html">About</a> <ul> <li><a href="history.html">Company History</a></li> <li><a href="staff.html">Our Staff</a></li> <li><a href="press.html">Press Releases</a></li> <li><a href="investorInfo.html">Investor Information</a></li> </ul> </li> <li><a href="contact.html">Contact</a></li> </ul>---- Code Omitted ----
With this nested list in place and without changing the CSS, this page will display as follows:
![]()
By modifying the CSS, we can move the submenus over to the right and hide tehm until the user hovers over one of the parent menu items. Here are the steps:
-
Set the position of the main menu items to relative. Like with dropdown menus, we will need to position the submenus using absolute positioning:
#mainMenu li { position:relative; /*other declarations omitted*/ } -
Position the submenus absolutely and hide the submenus.
#mainMenu li ul { position:absolute; width:150px; left:118px; top:5px; display:none; } -
Style the submenu options.
#mainMenu li ul li { font-size:smaller; } -
Display the submenu when the user hovers over the main option. The background-color declaration is necessary for Internet Explorer 7. Without it, the submenus can disappear while the user is hovering over them.
#mainMenu li:hover ul { display:block; background-color:#fff; /*for IE7*/ } -
Position a tags relatively. This is another fix for Internet Explorer 7. If the a tags are left statically positioned, then they won't fill the full width of their parent list items and the menus will only work when users hover over the text of the link.
#mainMenu a { position:relative; /*for IE7*/ /*other declarations omitted*/ }
Exercise: Combining Dropdown and Flyout Menus
In this exercise, you'll modify a working dropdown menu so that third-level options will flyout to the right as shown in the screenshot below:
- Open CssListMenus/Exercises/CssMenu-mixed.html in your browser.
- Hover over the About menu. You should see this:
- Notice the third-level menu. It is currently not functional.
- Hover over the About menu. You should see this:
- Open CssListMenus/Exercises/CssMenu-mixed.html in your editor.
- Change the CSS so that the third-level menu is functional and flies out to the right.
The full code is shown below:
Code Sample: CssListMenus/Demos/CssMenu-flyout.html
---- Code Omitted ----<link type="text/css" rel="stylesheet" href="../reset-meyer.css" /> <style type="text/css"> #mainMenu { margin:10px; width:120px; font-family: "Trebuchet MS"; } #mainMenu li { position:relative; display:block; border:1px solid #000; border-top:0px; } #mainMenu li:first-child { border-top:1px solid #000; } #mainMenu a { position:relative; /*for IE7*/ display:block; padding:3px; text-decoration:none; color:#009; } #mainMenu a:hover { background-color:#009; color:#fff; } #mainMenu li ul { position:absolute; width:150px; left:118px; top:5px; display:none; } #mainMenu li ul li { font-size:smaller; } #mainMenu li:hover ul { display:block; } </style>---- Code Omitted ----
Open CssListMenus/Demos/CssMenu-flyout.html in your browser to see it in action.
- In the HTML, you'll notice the "Corporate Governance" bullet has a submenu that is commented out. Uncomment it.
- Modify your CSS so that this new submenu is also function and flies out when the user hovers over "Corporate Governance", but not before:
- Hint: you will only need to change one character.
Accessibility
Navigation menus marked up as lists are much more accessible than menus marked up in tables or nested divs. One way to get a feel for this is to turn off CSS in the browser to see if the menu is still navigable. In Firefox, you can do this by choosing View > Page Style > No Style from the main menu. When we look at CssListMenus/Solutions/CssMenu-mixed-challenge.html in this view, here's what we see:
This is how a screen reader might "see" the page. Because of the logical structure, it should have no problem presenting it correctly.
CSS Lists as Hierarchical Navigation Conclusion
In this lesson of the CSS tutorial, you have learned to use lists for accesible static and dynamic navigation menus.
Footnotes
-
For browsers such as Internet Explorer 6 that don't support the :first-child pseudo-class, you can add a "first" class to the first list item and apply the style to the #mainMenu li.first selector.
-
Stu Nichols has succeeded in creating a dropdown menu that works in Internet Explorer 6 without using JavaScript. See http://www.cssplay.co.uk/menus/final_drop.html. His solution, which is copyrighted, makes heavy use of CSS hacks and Internet Explorer conditional comments.