The CSS Anthology: 101 Essential Tips, Tricks and Hacks, Chapter 4 – Navigation

Unless you limit yourself to one-page web sites, you’ll need to design navigation. In fact, navigation is among the most important parts of any web design, and requires a great deal of thought if visitors are to move around your site easily.

Making site navigation easy is one area in which CSS really comes into its own. Older methods of creating navigation tended to rely on lots of images, nested tables, and JavaScript – all of which can seriously affect the usability and accessibility of a site. If your site cannot be navigated using a device that lacks JavaScript support, for example, you risk blocking users who have turned JavaScript off, as well as locking out text-only devices such as screen readers and search engine robots – they’ll never penetrate past your home page to index the content of your site. If your design clients seem unconcerned about accessibility, tell them their clunky menu is stopping them from achieving a decent search engine ranking!

CSS allows you to create attractive navigation that, in reality, is no more than text – text that can be marked up in such a way as to ensure that it’s both accessible and understandable by all those who are unable to physically see your design, but still want to access your content. In this chapter, we’ll look at a variety of solutions for creating CSS-based navigation. Some are suited to implementation on an existing site, to make it load more quickly and boost its accessibility by replacing an old-fashioned, image-based navigation. Others are more suited to incorporation within a pure CSS layout.

How do I style a structural list as a navigation menu?

Navigation is essentially a list of places to visit on your site, so marking up navigation menus as lists makes sense semantically and we can hook our CSS styles to the list elements themselves. However, we want to avoid our navigation looking like a standard bulleted list as rendered by the browser’s internal style sheet.

Solution

The navigation in the figure below is marked up as a list and styled using CSS, as you can see here.

Creating navigation by styling a list

Here’s the markup required to create the navigation list:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
 <head>
   <title>Lists as navigation</title>
   <meta http-equiv="content-type" content="text/html;  
       charset=utf-8" />
   <link rel="stylesheet" type="text/css" href="listnav1.css" />
 </head>
 <body>
   <div id="navigation">
     <ul>
       <li><a href="#">Recipes</a></li>
       <li><a href="#">Contact Us</a></li>
       <li><a href="#">Articles</a></li>
       <li><a href="#">Buy Online</a></li>
     </ul>
   </div>
 </body>
</html>

Here’s the complete CSS that transforms our dull unordered list into an attractive menu:

#navigation { 
 width: 200px;
}
#navigation ul {
 list-style: none;
 margin: 0;
 padding: 0;
}
#navigation li {
 border-bottom: 1px solid #ED9F9F;
}
#navigation li a:link, #navigation li a:visited  {
 font-size: 90%;
 display: block;
 padding: 0.4em 0 0.4em 0.5em;
 border-left: 12px solid #711515;
 border-right: 1px solid #711515;
 background-color: #B51032;
 color: #FFFFFF;
 text-decoration: none;
}
Discussion

To create navigation based on an unordered list – first create your list, placing each navigation link inside a li element:

  <ul> 
   <li><a href="#">Recipes</a></li>
   <li><a href="#">Contact Us</a></li>
   <li><a href="#">Articles</a></li>
   <li><a href="#">Buy Online</a></li>
 </ul>

Next, wrap the list in a div with an appropriate ID:

<div id="navigation"> 
 <ul>
   <li><a href="#">Recipes</a></li>
   <li><a href="#">Contact Us</a></li>
   <li><a href="#">Articles</a></li>
   <li><a href="#">Buy Online</a></li>
 </ul>
</div>

As the following figure shows, this markup looks fairly ordinary with the browser’s default styles applied.

A very basic, unstyled list

The first job we need to do is style the container in which the navigation sits – in this case, navigation:

#navigation { 
 width: 200px;
}

I’ve given navigation a width. If this navigation system were part of a CSS page layout, I’d probably add some positioning information to this ID as well.

Next, we style the list:

#navigation ul { 
 list-style: none;
 margin: 0;
 padding: 0;
}

As the figure below illustrates, the above rule removes list bullets and the indented margin that browsers apply, by default, when displaying a list.

Viewing the list after indentation and bullets are removed

The next step is to style the li elements within navigation, to give them a bottom border:

#navigation li { 
 border-bottom: 1px solid #ED9F9F;
}

Finally, we style the link itself:

#navigation li a:link, #navigation li a:visited  { 
 font-size: 90%;
 display: block;
 padding: 0.4em 0 0.4em 0.5em;
 border-left: 12px solid #711515;
 border-right: 1px solid #711515;
 background-color: #B51032;
 color: #FFFFFF;
 text-decoration: none;
}

Most of the work is done here, creating CSS rules to add left and right borders, removing the underline, and so on. The first property declaration in this rule sets the display property to block. This causes the link to display as a block element, meaning that the whole area of each navigation “button” is active when you move the cursor over it – the same effect you’d see if you used an image for the navigation.

How do I use CSS to create rollover navigation without images or JavaScript?

Site navigation often features a rollover effect: when a user holds the cursor over a menu button, a new button image displays, creating a highlighting effect. To achieve this effect using image-based navigation, you need to use two images and JavaScript.

Solution

Using CSS to build your navigation makes the creation of attractive rollover effects far simpler than it would be if you used images. The CSS rollover is created using the :hover pseudo-class selector – the same selector you’d use to style a hover state for your links.

Let’s take the above list navigation example and add the following rule to create a rollover effect:

#navigation li a:hover { 
 background-color: #711515;
 color: #FFFFFF;
}

The figure below shows what the menu looks like when the cursor is positioned over the first menu item.

The CSS navigation showing a rollover effect

Discussion

The CSS we’ve used to create this effect is very simple. You can create hover states for heavily styled links just as you can for standard links. In this example, I simply changed the background color to make it the same as the left-hand border; however, you could alter the background, text, and border color to create interesting effects for the navigation.

Hover Here? Hover There!

In modern browsers, including Internet Explorer 7, you can apply the :hover pseudo-selector to any element you like, but in Internet Explorer 6 and below, you can apply it only to links.

Older versions of Internet Explorer allow only the anchor text to be made clickable, because the link fails to expand to fill its container (in this case, the list item). This means that the user is forced to click on the text, rather than the red background, to select the menu item.

One way to rectify this issue is to use a CSS hack that expands the width of the link – but only in Internet Explorer version 6 and earlier. Here’s the rule that does just that:

* html #navigation li a { 
 width: 100%;
}

Of course, you may decide that leaving the links as is and avoiding the hack is an acceptable compromise. We’ll cover cross-browser techniques in more detail in Chapter 7, Cross-browser Techniques.

Can I use CSS and lists to create a navigation system with subnavigation?

The examples we’ve seen so far in this chapter have assumed that you only have one navigation level to display. Sometimes, more than one level is necessary – but is it possible to create multi-leveled navigation using styled lists in CSS?

Solution

The perfect way to display subnavigation within a navigation system is to create a sublist within a list. The two levels of navigation will be easy to understand when they’re marked up in this way – even in browsers that lack support for CSS.

To produce multilevel navigation, we can edit the example we saw in the previous figure, adding a nested list and styling the colors, borders, and link properties of the new list’s items:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
<head>
<title>Lists as navigation</title>
<meta http-equiv="content-type"
   content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="listnav_sub.css" />
</head>
<body>
<div id="navigation">
 <ul>
   <li><a href="#">Recipes</a>
     <ul>
       <li><a href="#">Starters</a></li>
       <li><a href="#">Main Courses</a></li>
       <li><a href="#">Desserts</a></li>
     </ul>
   </li>
   <li><a href="#">Contact Us</a></li>
   <li><a href="#">Articles</a></li>
   <li><a href="#">Buy Online</a></li>
 </ul>
</div>
</body>
</html>
#navigation { 
 width: 200px;
}
#navigation ul {
 list-style: none;
 margin: 0;
 padding: 0;
}
#navigation li {
 border-bottom: 1px solid #ED9F9F;
}
#navigation li a:link, #navigation li a:visited  {
 font-size: 90%;
 display: block;
 padding: 0.4em 0 0.4em 0.5em;
 border-left: 12px solid #711515;
 border-right: 1px solid #711515;
 background-color: #B51032;
 color: #FFFFFF;
 text-decoration: none;
}
#navigation li a:hover {
 background-color: #711515;
 color: #FFFFFF;
}
#navigation ul ul {
 margin-left: 12px;
}
#navigation ul ul li {
 border-bottom: 1px solid #711515;
 margin:0;
}
#navigation ul ul a:link, #navigation ul ul a:visited {
 background-color: #ED9F9F;
 color: #711515;
}
#navigation ul ul a:hover {
 background-color: #711515;
 color: #FFFFFF;
}

The result of these additions is shown in the figure below.

The CSS list navigation containing subnavigation

Discussion

Nested lists are a perfect way to describe the navigation system that we’re working with here. The first list contains the main sections of the site, while the sublist under Recipes shows the subsections within the Recipes category. Even without any CSS styling, the structure of the list is still clear and comprehensible, as you can see in the figure below.

The navigation remaining logical without the CSS

The HTML that we use to mark up this list simply nests the sublist inside the li element of the appropriate main item:

<div id="navigation">  
 <ul>  
   <li><a href="#">Recipes</a>  
     <ul>  
       <li><a href="#">Starters</a></li>  
       <li><a href="#">Main Courses</a></li>  
       <li><a href="#">Desserts</a></li>  
     </ul>  
   </li>  
   <li><a href="#">Contact Us</a></li>  
   <li><a href="#">Articles</a></li>  
   <li><a href="#">Buy Online</a></li>  
 </ul>  
</div>

With this HTML, and without any changes to the CSS, the menu will display as shown in the figure below on the left, where the li elements inherit the styles of the main menu.

Let’s add a style rule for the nested list to communicate visually that it’s a submenu, distinct from the main navigation:

#navigation ul ul {  
 margin-left: 12px;  
}

This rule will indent the nested list so that it’s in line with the right edge of the border for the main menu, as demonstrated in the following figure on the right.

The sublist taking on the styles of the main navigation and the indented version

Let’s add some simple styles to the li and a elements within the nested list to complete the effect:

#navigation ul ul li {  
 border-bottom: 1px solid #711515;  
 margin: 0;  
}  
#navigation ul ul a:link, #navigation ul ul a:visited {  
 background-color: #ED9F9F;  
 color: #711515;  
}  
#navigation ul ul a:hover {  
 background-color: #711515;  
 color: #FFFFFF;  
}

How do I make a horizontal menu using CSS and lists?

All the examples we’ve seen in this chapter have dealt with vertical navigation – the kind of navigation that will most likely be found in a column to the left or right of a site’s main content area. However, site navigation is also commonly found as a horizontal menu close to the top of the document.

Solution

As the figure below shows, this type of menu can be created using styled lists in CSS. The li elements must be set to display inline to avoid that line break between list items.

Using CSS to create horizontal list navigation

Here’s the HTML and CSS that creates this display:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">  
<head>  
<title>Lists as navigation</title>  
<meta http-equiv="content-type"  
   content="text/html; charset=utf-8" />  
<link rel="stylesheet" type="text/css" href="listnav_horiz.css" />  
</head>  
<body>  
<div id="navigation">  
 <ul>  
   <li><a href="#">Recipes</a></li>  
   <li><a href="#">Contact Us</a></li>  
   <li><a href="#">Articles</a></li>  
   <li><a href="#">Buy Online</a></li>  
 </ul>  
</div>  
</body>  
</html>
body {  
 padding: 1em;  
}  
#navigation {  
 font-size: 90%;  
}  
#navigation ul {  
 list-style: none;  
 margin: 0;  
 padding: 0;  
 padding-top: 1em;  
}  
#navigation li {  
 display: inline;  
}  
#navigation a:link, #navigation a:visited {  
 padding: 0.4em 1em 0.4em 1em;  
 color: #FFFFFF;  
 background-color: #B51032;  
 text-decoration: none;  
 border: 1px solid #711515;  
}  
#navigation a:hover {  
 color: #FFFFFF;  
 background-color: #711515;  
}
Discussion

To create the horizontal navigation, we start with a list that’s identical to the one we created for our vertical list menu:

<div id="navigation">  
 <ul>  
   <li><a href="#">Recipes</a></li>  
   <li><a href="#">Contact Us</a></li>  
   <li><a href="#">Articles</a></li>  
   <li><a href="#">Buy Online</a></li>  
 </ul>  
</div>

We style the #navigation container to apply some basic font information, as we did with the vertical navigation. In a CSS layout, this ID would probably also contain some additional styles that determine the navigation’s position on the page:

#navigation {  
 font-size: 90%;  
}

In styling the ul element, we remove the list bullets and default indentation applied to the list by the browser:

#navigation ul {  
 list-style: none;  
 margin: 0;  
 padding: 0;  
 padding-top: 1em;  
}

The property that transforms our list from a vertical to a horizontal display is applied to the li element. After we set the display property to inline, the list looks like the figure below:

#navigation li {  
 display: inline;  
}

Displaying the list menu horizontally

All that’s left for us to do is to style the links for our navigation:

#navigation a:link, #navigation a:visited {  
 padding: 0.4em 1em 0.4em 1em;  
 color: #FFFFFF;  
 background-color: #B51032;  
 text-decoration: none;  
 border: 1px solid #711515;  
}  
#navigation a:hover {  
 color: #FFFFFF;  
 background-color: #711515;  
}

If you’re creating boxes around each link – as I have here – remember that, in order to make more space between the text and the edge of its container, you’ll need to add more left and right padding to the links. To create more space between the navigation items, add left and right margins to the links.

How do I create button-like navigation using CSS?

Navigation that appears to be composed of clickable buttons is a feature of many web sites. This kind of navigation is often created using images to which effects are applied to make the edges look beveled and button-like. Often, some JavaScript code is used to swap in another image, so the button appears to depress when the user holds the cursor over it or clicks on the image.

This brings up the question: Is it possible to create such button-like navigation systems using only CSS? Absolutely!

Solution

Creating a button effect like that shown below is possible, and fairly straightforward, using CSS. The effect’s success hinges on your use of the CSS border properties.

Building button-like navigation with CSS

Here’s the code you’ll need:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">  
<head>  
<title>Lists as navigation</title>  
<meta http-equiv="content-type"  
   content="text/html; charset=utf-8" />  
<link rel="stylesheet" type="text/css" href="listnav_button.css"  
   />  
</head>  
<body>  
<div id="navigation">  
 <ul>  
   <li><a href="#">Recipes</a></li>  
   <li><a href="#">Contact Us</a></li>  
   <li><a href="#">Articles</a></li>  
   <li><a href="#">Buy Online</a></li>  
 </ul>  
</div>  
</body>  
</html>

#navigation {  
 font-size:90%  
}  
#navigation ul {  
 list-style: none;  
 margin: 0;  
 padding: 0;  
 padding-top: 1em;  
}  
#navigation li {  
 display: inline;  
}  
#navigation a:link, #navigation a:visited {  
 margin-right: 0.2em;  
 padding: 0.2em 0.6em 0.2em 0.6em;  
 color: #A62020;  
 background-color: #FCE6EA;  
 text-decoration: none;  
 border-top: 1px solid #FFFFFF;  
 border-left: 1px solid #FFFFFF;  
 border-bottom: 1px solid #717171;  
 border-right: 1px solid #717171;  
}  
#navigation a:hover {  
 border-top: 1px solid #717171;  
 border-left: 1px solid #717171;  
 border-bottom: 1px solid #FFFFFF;  
 border-right: 1px solid #FFFFFF;  
}

Discussion

To create this effect, we'll use the horizontal list navigation described in the section called "How do I make a horizontal menu using CSS and lists?". However, to create the button look, we'll use different colored borders at the top and left than we use for the bottom and right sides of each button. By giving the top and left edges of the button a lighter colored border than we assign to the button's bottom and right edges, we create a slightly beveled effect:

#navigation a:link, #navigation a:visited {  
 margin-right: 0.2em;  
 padding: 0.2em 0.6em 0.2em 0.6em;  
 color: #A62020;  
 background-color: #FCE6EA;  
 text-decoration: none;  
 border-top: 1px solid #FFFFFF;  
 border-left: 1px solid #FFFFFF;  
 border-bottom: 1px solid #717171;  
 border-right: 1px solid #717171;  
}

We reverse the border colors for the hover state, which creates the effect of the button being pressed:

#navigation a:hover {  
 border-top: 1px solid #717171;  
 border-left: 1px solid #717171;  
 border-bottom: 1px solid #FFFFFF;  
 border-right: 1px solid #FFFFFF;  
}

Try using heavier borders and changing the background images on the links, to create effects that suit your design.

How do I create tabbed navigation with CSS?

Navigation that appears as tabs across the top of the page is a popular navigation choice. Many sites create tabs using images. However, this can be less accessible and also problematic if your navigation is created using a Content Management System, with users of that system being able to add tabs or change the text in the tabs. However, it's possible to create a tab effect by combining background images and text styled with CSS.
Solution

The tabbed navigation shown below can be created by styling a horizontal list.

Building button-like navigation with CSS

Here's the HTML and CSS that creates this effect:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"   
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">  
<head>  
<title>Lists as navigation</title>  
<meta http-equiv="content-type"  
   content="text/html; charset=utf-8" />  
<link rel="stylesheet" type="text/css" href="tabs.css" />  
</head>  
<body id="recipes">  
<div id="header">  
<ul>  
 <li class="recipes"><a href="#">Recipes</a></li>  
 <li class="contact"><a href="#">Contact Us</a></li>  
 <li class="articles"><a href="#">Articles</a></li>  
 <li class="buy"><a href="#">Buy Online</a></li>  
</ul>  
</div>  
<div id="content">  
<h1>Recipes</h1>  
<p>Lorem ipsum dolor sit amet, ... </p>  
</div>  
</body>  
</html>
body {   
 font: .8em/1.8em verdana, arial, sans-serif;  
 background-color: #FFFFFF;  
 color: #000000;  
 margin: 0 10% 0 10%;  
}  
 
#header {  
 float: left;  
 width: 100%;  
 border-bottom: 1px solid #8DA5FF;  
 margin-bottom: 2em;  
}  
 
#header ul {  
 margin: 0;  
 padding: 2em 0 0 0;  
 list-style: none;  
}  
 
#header li {  
 float: left;  
 background-image: url("images/tab_left.gif");  
 background-repeat: no-repeat;  
 margin: 0 1px 0 0;  
 padding: 0 0 0 8px;  
}  
 
#header a {  
 float: left;  
 display: block;  
 background-image: url("images/tab_right.gif");  
 background-repeat: no-repeat;  
 background-position: right top;  
 padding: 0.2em 10px 0.2em 0;  
 text-decoration: none;  
 font-weight: bold;  
 color: #333366;  
}  
 
#recipes #header li.recipes,  
#contact #header li.contact,  
#articles #header li.articles,  
#buy #header li.buy {  
 background-image: url("images/tab_active_left.gif");  
}  
 
#recipes #header li.recipes a,  
#contact #header li.contact a,  
#articles #header li.articles a,  
#buy #header li.buy a {  
 background-image: url("images/tab_active_right.gif");  
 background-color: transparent;  
 color:#FFFFFF;  
}  
Discussion

The tabbed navigation approach I've used here is a basic version of Douglas Bowman's Sliding Doors of CSS method, which is a tried and tested technique for creating a tabbed interface. The structure that I've given to the navigation menu is the same kind of simple unordered list that we've worked with throughout this chapter, except that each list item is assigned a class attribute that describes the link it contains. We've also wrapped the entire list in a div with an id of header. The technique takes its name from the two images used to implement it - one overlaps the other, and the images slide apart as the text size increases.

You'll need four images to create this effect: two to create the regular tab color, and two to use when the tab is the currently selected (highlighted) tab. The images I've used in this example are shown below. As you can see, they're far wider and taller than would generally be necessary for a tab - this provides plenty of space for the tab to grow if the user's browser is configured to display text at a very large size.

The image files used to create the tabs

Here's the basic list of navigation items:

<div id="header">   
<ul>  
 <li class="recipes"><a href="#">Recipes</a></li>  
 <li class="contact"><a href="#">Contact Us</a></li>  
 <li class="articles"><a href="#">Articles</a></li>  
 <li class="buy"><a href="#">Buy Online</a></li>  
</ul>  
</div>

The first step is to style the container that surrounds the navigation. We're going to give our header a simple bottom border for the purposes of this exercise, but on a real, live web site this container may hold other elements in addition to our tabs (such as a logo or search field):

#header {   
 float: left;  
 width: 100%;  
 border-bottom: 1px solid #8DA5FF;  
 margin-bottom: 2em;  
}

As you'll have noticed, we float the header to the left. We'll also float the individual list items; floating the container that houses them ensures that they remain contained once they're floated, and that the border will display below them.

Next, we create a style rule for the ul element inside the header:

#header ul {   
 margin: 0;  
 padding: 2em 0 0 0;  
 list-style: none;  
}

This rule removes the bullets and alters the margin and padding on our list - we've added two ems of padding to the top of the ul element. The figure below shows the results of our work so far.

Displaying the navigation after styling the ul element

Now we need to style the list items:

#header li {   
 float: left;  
 background-image: url("images/tab_left.gif");  
 background-repeat: no-repeat;  
 margin: 0 1px 0 0;  
 padding: 0 0 0 8px;  
}

This rule uses the float property to position the list items horizontally while maintaining the block-level status of each. We then add the first of our sliding door images - the thin left-hand side of the tab - as a background image. A single-pixel right margin on the list item creates a gap between one tab and the next. The figure below shows that the left-hand tab image now appears for each tab.

The navigation tabs reflecting the new styles

Next, we style the links, completing the look of our tabs in their unselected state. The image that forms the right-hand side of the tab is applied to each link, completing the tab effect:

#header a {   
 float: left;  
 display: block;  
 background-image: url("images/tab_right.gif");  
 background-repeat: no-repeat;  
 background-position: right top;  
 padding: 0.2em 10px 0.2em 0;  
 text-decoration: none;  
 font-weight: bold;  
 color: #333366;  
}

The results are shown in the figure below.

Styling the navigation links

If you increase the text size in the browser, you can see that the tabs neatly increase in size too. In fact, they do so without overlapping and without the text protruding out of the tab - this is because we have used images that allow plenty of room for growth.

To complete the tab navigation, we need to highlight the tab that corresponds to the currently displayed page. You'll recall that each list item has been assigned a unique class name. If we assign to the body element an ID that has a value equal to the value of each list item class, CSS can do the rest of the work:

<body id="recipes">

Although it looks like a lot of code, the CSS code that styles the tab matching the body ID is relatively straightforward. The images I've used are exact copies of the left and right images that we applied to the tabs, but they're a different color, which produces the effect of one tab appearing to be highlighted.

Here's the CSS:

#recipes #header li.recipes,   
#contact #header li.contact,  
#articles #header li.articles,  
#buy #header li.buy {  
 background-image: url("images/tab_active_left.gif");  
}  
 
#recipes #header li.recipes a,  
#contact #header li.contact a,  
#articles #header li.articles a,  
#buy #header li.buy a {  
 background-image: url("images/tab_active_right.gif");  
 background-color: transparent;  
 color: #FFFFFF;  
}

With these rules in place, specifying an ID of recipes to our body will cause the Recipes tab to be highlighted, specifying contact will cause the Contact Us tab to be highlighted, and so on. The results of this work are shown in the figure below.

Identifying a Useful Technique

The technique of adding an ID to the body element can be very useful. For example, you may have various color schemes for different sections of your site to help the user identify which section they're using. You can simply add the section name to the body element and make use of it within the style sheet, as we did in this example.

Highlighting the Contact Us tab by specifying contact as the ID of the body element

How can I visually indicate which links are external to my site?

When linking to other content it's a nice touch to visually demonstrate to users when a link is to another site. We can do this using CSS without needing to add anything to our markup.

Solution

We can use a CSS3 selector that's supported in many modern browsers to select the external links. The first link in the paragraph below is to a page on our own site, the second to an external web site (Google):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"    
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">  
 <head>  
   <title>Chapter 4 - Show external links</title>  
   <meta http-equiv="content-type" content="text/html;    
       charset=utf-8" />  
   <link rel="stylesheet" type="text/css"    
       href="external_links.css" />  
 </head>  
 <body>  
 <p>Lorem ipsum dolor sit amet, <a href="page2.html">consectetur    
     adipiscing elit</a>. Aenean porta. Donec eget quam. Morbi    
     libero.Curabitur ut justo vehicula elit feugiat lacinia. Morbi  
     ac quam. <a href="http://www.google.com">Sed venenatis</a>,    
     lectus quis porta viverra, lectus sapien tempus odio, ac    
     volutpat mi dolor ac elit.</p>  
 </body>  
</html>

We can use a CSS3 selector to target the link that starts with http: and add an icon to it:

a[href ^="http:"] {   
 padding-left: 20px;  
 background-image: url(link_icon_external.gif);  
 background-repeat: no-repeat;  
}

The external link displays with an icon

Any links on our page that start with http: (which should be external as it is unnecessary to link to pages on our own site like that) will display with the world icon.

Discussion

This CSS3 attribute selector is widely supported in modern browsers, although it will be ignored in Internet Explorer 6. In browsers that lack support for this selector the link will just display as normal; so, it's a nice enhancement for browsers with support but leaves the experience unchanged for those with older browsers.

Let's take a closer look at that selector: a[href ^="http:"].

The attribute that we're selecting is the href attribute, and we want our selector to match when it finds the text http: at the beginning of the attribute value. The ^= operator means "begins with". You could use a similar selector to match all email links, for example, a[href ^="mailto:"].

Another useful attribute selector is to select on the file extension of a link. This means you can add a small icon to show that a document is a PDF or other document type, depending on the extension. The selector a[href $=".pdf"] will match any link that has a file extension of .pdf. The $= operator means "ends with", so this selector will match when an href attribute value ends with .pdf. The example below shows all three types in action:

<ul class="links">   
 <li><a href="http://www.google.com">Go somewhere else</a></li>  
 <li><a href="/files/example.pdf">Download a PDF</a></li>  
 <li><a href="mailto:info@example.com">Email someone</a></li>  
</ul>
a[href ^="http:"] {   
 padding-left: 20px;  
 background-image: url(link_icon_external.gif);  
 background-repeat: no-repeat;  
}  
 
a[href ^="mailto:"] {  
 padding-left: 20px;  
 background-image: url(link_icon_email.gif);  
 background-repeat: no-repeat;  
}  
 
a[href $=".pdf"] {  
 padding-left: 20px;  
 background-image: url(link_icon_pdf.gif);  
 background-repeat: no-repeat;  
}

Links with icons for external and email links, and PDF files

(The icons you can see above are from http://www.famfamfam.com/lab/icons/silk/.)

Attribute selectors are a very useful part of CSS and you can safely use them in this kind of situation where you're just adding an enhancement to your design.

How do I change the cursor type?

It's common for the cursor to change to a hand icon when the cursor's moved over a link on any part of the page. Occasionally - perhaps to fit in with a particular interface - you might want to change the cursor to represent a different action.

Solution

We change the cursor using the CSS cursor property. For example, if we wanted to change the cursor on anchor elements that link to help documentation we can specify the style like so:

a.help {   
 cursor: help;  
}

The figure below identifies the properties that are available in CSS 2.1, and how they appear in Internet Explorer 8.

The CSS 2.1 Standard Cursors in IE8

Discussion

The cursor property can take a range of values. Changing the cursor display can be a useful way for web applications with friendly interfaces to provide valuable user feedback. For example, you might decide to use a question mark cursor for indicating help text.

Changing the Cursor Can Cause Confusion!

You should use this effect with care, and keep in mind that people are generally used to standard browser behavior. For instance, users are familiar with the cursor representing a pointing hand icon when hovered over a link.

The figure above the various properties that are available in the CSS standard; these are supported by most modern browsers, including Internet Explorer 6 and above, Safari, Opera, Firefox, and Chrome. Browser support for the complete range of values varies so make sure to test.

CSS3 increases the range of cursor values available, as shown below, but browser support for these values varies. They're well supported by Safari, Firefox, and Chrome, and IE8 supports most of them; however, Opera, as of the time of writing, only supports CSS 2.1 cursor values.

New CSS3 Cursors

How do I create rollover images in my navigation without using JavaScript?

CSS-based navigation can provide some really interesting effects, but there are still some effects that require the use of images. Is it possible to enjoy the advantages of text-based navigation and still use images?

Solution

It is possible to combine images and CSS to create JavaScript-free rollovers. This solution is based on a technique described at WellStyled.com. Here's the code you'll need:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"    
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">    
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">    
<head>    
<title>Lists as navigation</title>    
<meta http-equiv="content-type"    
   content="text/html; charset=utf-8" />    
<link rel="stylesheet" type="text/css" href="images.css" />    
</head>    
<body>    
<ul id="nav">    
 <li><a href="#">Recipes</a></li>    
 <li><a href="#">Contact Us</a></li>    
 <li><a href="#">Articles</a></li>    
 <li><a href="#">Buy Online</a></li>    
</ul>    
</body>    
</html>
ul#nav {    
 list-style-type: none;    
 padding: 0;    
 margin: 0;    
}    
#nav a:link, #nav a:visited {    
 display: block;    
 width: 150px;    
 padding: 10px 0 16px 32px;    
 font: bold 80% Arial, Helvetica, sans-serif;    
 color: #FF9900;    
 background: url("peppers.gif") top left no-repeat;    
 text-decoration: none;    
}    
#nav a:hover {    
 background-position: 0 -69px;    
 color: #B51032;    
}    
#nav a:active {    
 background-position: 0 -138px;    
 color: #006E01;    
}

The results can be seen in the figure below, but to enjoy the full effect I suggest you try it for yourself. Remember to click on a link or two!

Using images to advantage in the completed menu

Discussion

This solution offers a means of using images in your navigation without having to resort to preloading lots of separate files.

The navigation has three states, but there's no need to use three separate images to depict these states. Instead, we use one large image that contains the graphics for all three states, as shown below.

All three rollover states

The navigation is marked up as a simple list:

<ul id="nav">    
 <li><a href="#">Recipes</a></li>    
 <li><a href="#">Contact Us</a></li>    
 <li><a href="#">Articles</a></li>    
 <li><a href="#">Buy Online</a></li>    
</ul>

We control the display of the background image within the declaration block for the navigation links. However, because the image is far bigger than the area required for this element, we only see the yellow pepper at first:

#nav a:link, #nav a:visited {    
 display: block;    
 width: 150px;    
 padding: 10px 0 16px 32px;    
 font: bold 80% Arial, Helvetica, sans-serif;    
 color: #FF9900;    
 background: url("peppers.gif") top left no-repeat;    
 text-decoration: none;    
}

When the :hover state is activated, the background image moves up the exact number of pixels required to reveal the red pepper. In this example, I had to move it by 69 pixels, but this figure will vary depending on the image that you use. You could probably work it out mathematically, or you could do as I do and simply increment the background position a few pixels at a time, until it appears in the right location on hover:

#nav a:hover {    
 background-position: 0 -69px;    
 color: #B51032;    
}

When the :active state is activated, the background image shifts again, this time to display the green pepper when the link is clicked:

#nav a:active {    
 background-position: 0 -138px;    
 color: #006E01;    
}

That's all there is to it! The effect can fall apart if the user resizes the text in the browser to a larger font, which allows the edges of the hidden images to display. You can anticipate this to some degree by leaving quite a large space between each of the three images - keep this in mind when preparing your images.

Image Flickering in Internet Explorer

This technique sometimes causes the navigation to flicker in Internet Explorer. In my tests, this only tends to be a problem when the image is larger than the ones we've used here; however, if your navigation items flicker, a well-documented remedy is available.

How should I style a site map?

A site map is a helpful page on your web site that lists all pages in the site. It can help those who are unable to find what they're looking for through the navigation - as well as providing a quick way to see what's available at a glance and go to it with one click.
Solution

A site map is really a list of all of the destinations available on your site and so is ideally marked up as a set of nested lists. The first list is your main navigation, with the internal navigation nested within each main navigation point. A list works even if your site structure has many levels and should be easy to generate from your content management system. The figure below displays the results of the following code:

<ul id="sitemap">    
 <li><a href="/about">About us</a>    
 <ul>    
   <li><a href="/about/team">The team</a></li>    
   <li><a href="/about/history">Our history</a></li>    
 </ul>    
 </li>    
 <li><a href="/products">Our products</a></li>    
 <li><a href="/order">Ordering information</a>    
 <ul>    
   <li><a href="/order/shops">Our shops</a></li>    
   <li><a href="/order/stockists">Other stockists</a></li>    
   <li><a href="/order/onlinestockists">Online stockists</a></li>    
 </ul>    
 </li>    
 <li><a href="/contact">Contact us</a></li>    
</ul>
ul#sitemap {    
 margin: 0;    
 padding: 0;    
 list-style: none;    
}    
   
ul#sitemap ul {    
 padding-left: 1em;    
 list-style: none;    
}    
   
ul#sitemap li {    
 border-bottom: 2px solid #FFFFFF;    
}    
   
ul#sitemap li a:link, ul#sitemap li a:visited{    
 background-color: #CCCCCC;    
 display: block;    
 padding: 0.4em;    
 text-decoration: none;    
 color: #057FAC;    
}    
   
ul#sitemap li a:hover {    
 background-color: #999999;    
 color: #FFFFFF;    
}    
   
ul#sitemap li li a:link, ul#sitemap li li a:visited{    
 background-color: #FFFFFF;    
 display: block;    
 padding: 0.4em;    
}    
   
ul#sitemap li li a:hover {    
 background-color: #FFFFFF;    
 color: #057FAC;    
}

The styled sitemap

Discussion

The sitemap starts life as a list for the main navigation elements with the submenus nested inside - in the same way as the list with subnavigation discussed earlier in this chapter. The difference with the sitemap is that all menus will display their subnavigation. If the sitemap becomes deeper (with further levels), you just continue nesting in the same way, with subpages being a sublist of their parent page.

Take care to nest the list items properly. The submenu needs to go before the closing </li> of the parent list. Without CSS the sitemap displays as in the figure below. We can then style the parent list and sublists. I'm taking the margins and padding off the main list, but giving nested lists a left padding of 1em to indent them and make it clear that they're nested inside their parent list item:

Figure 4.22. The marked up sitemap without CSS

ul#sitemap {    
 margin: 0;    
 padding: 0;    
 list-style: none;    
}    
   
ul#sitemap ul {    
 padding-left: 1em;    
 list-style: none;    
}

I then want to give the main list items a strong style to show that they represent the main sections of my site. As with the navigation, I put most of the styling onto the a element and set the display property to block, so as to make the full width of the item clickable, as opposed to just the link text itself:

ul#sitemap li {    
 border-bottom: 2px solid #FFFFFF;    
}    
   
ul#sitemap li a:link, ul#sitemap li a:visited{    
 background-color: #CCCCCC;    
 display: block;    
 padding: 0.4em;    
 text-decoration: none;    
 color: #057FAC;    
}    
   
ul#sitemap li a:hover {    
 background-color: #999999;    
 color: #FFFFFF;    
}

As we're selecting elements within the sitemap list, we'll also select the nested a elements which should have no gray background color. So to finish off we need to deal with these elements with a more specific selector:

ul#sitemap li li a:link, ul#sitemap li li a:visited{    
 background-color: #FFFFFF;    
 display: block;    
 padding: 0.4em;    
}    
   
ul#sitemap li li a:hover {    
 background-color: #FFFFFF;    
 color: #057FAC;    
}

That's all there is to styling a sitemap using CSS. Just as with site navigation you can develop all kinds of creative effects working from this simple idea.

Can I create a drop-down menu using only CSS?

A previous edition of this book included a CSS-only drop-down menu that I have removed in this edition.

When this book was originally written, I - like many other web developers - was really looking forward to a utopia where we would just use CSS for everything, managing without JavaScript to create effects like drop-down menus. As we've learned more about these technologies and also about the ways in which people use the Web, I've come to the opinion that in this circumstance, JavaScript is a far better choice.

It is possible to create a drop-down navigation using only CSS. However, the techniques used to do this can actually be less accessible in practice than a well-thought through JavaScript-driven, drop-down menu would be. It's possible to make JavaScript menus navigable with the keyboard, for example, and to ensure that links are unhidden using display: none;, which renders them hidden for screen readers as well as those viewing the site on screen. If you really need a drop-down menu I'd advise taking a look at the excellent UDM4 menu, which can be styled using CSS but provides a good experience for all of your visitors.

How can I use CSS to keep image-based navigation clean and accessible?

While there are many benefits to using text-based navigation styled with CSS rather than images, it's likely that sometimes you'll need to use images to gain a particular effect or to use a certain font. When this happens, you can use all you know about CSS to ensure that the images are used in a way that is as problem-free as possible. This solution pulls together several different techniques to create a slick image-based navigation.
Solution

This solution starts with text-based navigation and replaces it, using CSS and a single image, with image-based navigation. The figure below shows us the final product, and here's the code:

<ul id="nav">    
 <li class="recipes"><a href="#"><span>Recipes</span></a></li>    
 <li class="contact"><a href="#"><span>Contact Us</span></a></li>    
 <li class="articles"><a href="#"><span>Articles</span></a></li>    
 <li class="buy"><a href="#"><span>Buy Online</span></a></li>    
</ul>
ul#nav {    
 width: 360px;    
 height: 30px;    
 overflow:hidden;    
 margin: 0;    
 padding: 0;    
 list-style: none;    
}    
   
ul#nav li {    
 float: left;    
}    
   
ul#nav li a span {    
 margin-left: -5000px;    
}    
   
ul#nav li a {    
 background-image: url(reflectonav.gif);    
 background-repeat: no-repeat;    
 display: block;    
 width: 75px;    
 overflow:hidden;    
}    
   
ul#nav li.recipes a {    
 background-position: 0 0;    
}    
   
ul#nav li.recipes a:hover {    
 background-position: 0 -42px;    
}    
   
ul#nav li.contact a {    
 background-position: -75px 0;    
 width: 105px;    
}    
   
ul#nav li.contact a:hover {    
 background-position: -75px -42px;    
}    
   
ul#nav li.articles a {    
 background-position: -180px 0;    
 width: 85px;    
}    
   
ul#nav li.articles a:hover {    
 background-position: -180px -42px;    
}    
   
ul#nav li.buy a {    
 background-position: -265px 0;    
 width: 85px;    
}    
   
ul#nav li.buy a:hover {    
 background-position: -265px -42px;    
}

The completed navigation

Discussion

In this solution we want to ensure that any text-only devices such as screen readers and search engines still understand our navigation, even though we're using images. Therefore, we start out as usual by creating an unordered list of navigation items. The only addition is a span element wrapped around the text inside the element:

<ul id="nav">    
 <li class="recipes"><a href="#"><span>Recipes</span></a></li>    
 <li class="contact"><a href="#"><span>Contact Us</span></a></li>    
 <li class="articles"><a href="#"><span>Articles</span></a></li>    
 <li class="buy"><a href="#"><span>Buy Online</span></a></li>    
</ul>

Our navigation is now just a structured list. Next, we need to create our images for the navigation. As with the rollover navigation image above we're going to use a composite image with several image states in it - in this case all of the navigation images and their rollover states in one image, as shown below.

The background image used in this example

Using one image saves making multiple requests to the server, and the file size for our one large image will be less that it would be if we had eight images chopped up. Now that we have our markup and image we can start to style the navigation using CSS. First, we remove the default browser styling on the ul element and float our list items left to make a horizontal navigation bar.

We also give the navigation width and height values. As the navigation is made up of images, we know how tall it will be and specifying the height ensures that there are no parts of the background showing through:

ul#nav {    
 width: 360px;    
 height: 30px;    
 overflow:hidden;    
 margin: 0;    
 padding: 0;    
 list-style: none;    
}    
   
ul#nav li {    
 float: left;    
}

We now want to hide the text from browsers that support images and CSS. We do this by setting a large negative margin on the span within the list items, throwing them off the left side of the screen:

ul#nav li a span {    
 margin-left: -5000px;    
}

We can now replace the text with the background image. Create a rule for the element in which display is set to block so it takes up the full area of the li, then add the background image:

ul#nav li a {    
 display: block;    
 background-image: url(reflectonav.gif);    
 background-repeat: no-repeat;    
 width: 75px;    
 overflow:hidden;    
}

If you look at your navigation in a browser after adding the above rules you'll see that it shows the "Recipes" item 4 times. This is because you've added the background image to each link in the navigation bar and the image displayed is positioned at the top left of that item, as the figure below shows.

After adding the background image to the element

To correct this situation we need to position the background image differently for each navigation item. As with the rollover images above, it's often simplest just to tweak the position pixel by pixel until it appears in the right place. The following CSS shows how we position the background for each link, and the figure below shows the results:

ul#nav li.recipes a {    
 background-position: 0 0;    
}    
   
ul#nav li.contact a {    
 background-position: -75px 0;    
 width: 105px;    
}    
   
ul#nav li.articles a {    
 background-position: -180px 0;    
 width: 85px;    
}    
   
ul#nav li.buy a {    
 background-position: -265px 0;    
 width: 85px;    
}

After positioning the background image

The final task we need to do is add our hover state. This is created in much the same way as the rollover background images in the earlier example. Using CSS, we can move the background image on hover so that the rollover state comes into view:

ul#nav li.recipes a:hover {    
 background-position: 0 -42px;    
}    
   
ul#nav li.contact a:hover {    
 background-position: -75px -42px;    
}    
   
ul#nav li.articles a:hover {    
 background-position: -180px -42px;    
}    
   
ul#nav li.buy a:hover {    
 background-position: -265px -42px;    
}

Summary

This chapter has discussed a range of different ways in which we can create navigation using structurally sound markup, as well as provided examples that can be used as starting points for your own experiments.

On existing sites where a full redesign is unfeasible, introducing a CSS-based navigation system can be a good way to improve the site's accessibility and performance without affecting its look and feel in a big way.

This article is chapter 4 from the SitePoint book The CSS Anthology: 101 Essential Tips, Tricks & Hacks, 3rd Edition, by Rachel Andrew. If you've enjoyed it, why not download the sample PDF which includes 3 more chapters from the book.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

No Reader comments

Comments on this post are closed.