Chapter 3
In This Chapter
Using CSS styles with lists
Building buttons from lists of links
Dynamically displaying sublists
Managing vertical and horizontal lists
Building CSS-based menus
Most pages consist of content and navigation tools. Almost all pages have a list of links somewhere on the page. Navigation menus are lists of links, but lists of links in plain HTML are ugly. There has to be a way to make ’em prettier.
It's remarkably easy to build solid navigation tools with CSS alone (at least, in the modern browsers that support CSS properly). In this chapter, you rescue your lists from the boring 1990s sensibility, turning them into dynamic buttons, horizontal lists, and even dynamically cascading menus.
HTML does provide some default list styling, but it's pretty dull. You often want to improve the appearance of a list of data. Most site navigation is essentially a list of links. One easy trick is to make your links appear as a set of buttons, as shown in Figure 3-1.
The buttons in Figure 3-1 are pretty nice. They have a 3D effect with shadows. They also act like buttons, with each button depressing when the mouse hovers over it. When you click one of these buttons, it acts like a link, taking you to another page, but they aren't really buttons at all, but a list, cleverly disguised to look and act like buttons.
If you look at the HTML, you'll be astonished at its simplicity:
<!DOCTYPE html>
<html lang = "en-US">
<head>
<meta charset = "UTF-8">
<title>buttonList.html</title>
<link rel = "stylesheet"
type = "text/css"
href = "buttonList.css" />
</head>
<body>
<h1>Button Lists</h1>
<div id = "menu">
<ul>
<li><a href = "http://www.google.com">Google</a></li>
<li><a href = "http://www.wiley.com">Wiley</a></li>
<li><a href = "http://www.wikipedia.org">Wikipedia</a></li>
<li><a href = "http://www.reddit.com">Reddit</a></li>
</ul>
</div>
</body>
</html>
As far as the HTML code is concerned, it's simply a list of links. There's nothing special here that makes this act like a group of buttons, except the creation of a div called menu. All the real work is done in CSS:
#menu li {
list-style-type: none;
width: 7em;
text-align: center;
margin-left: -2.5em;
}
#menu a {
text-decoration: none;
color: black;
display: block;
background-color: #EEEEFF;
box-shadow: 5px 5px 5px gray;
margin-bottom: 2px;
}
#menu a:hover {
background-color: #DDDDEE;
box-shadow: 3px 3px 3px gray;
border: none;
}
The process for turning an ordinary list of links into a button group like this is simply an application of CSS tricks:
It doesn't matter if you use an unordered or ordered list. Typically, the list will contain anchors to other pages. In this example, I'm using this list of links to some popular websites:
<div id = "menu">
<ul>
<li><a href = "http://www.google.com">Google</a></li>
<li><a href = "http://www.wiley.com">Wiley</a></li>
<li><a href = "http://www.wikipedia.org">Wikipedia</a></li>
<li><a href = "http://www.reddit.com">Reddit</a></li>
</ul>
</div>
Typically, you still have ordinary links on a page. To indicate that these menu links should be handled differently, put them in a div named menu. All the CSS-style tricks described here refer to lists and anchors only when they're inside a menu div.
This removes the bullets or numbers that usually appear in a list because these features distract from the effect you're aiming for (a group of buttons). Use CSS to specify how list items should be formatted when they appear in the context of the menu ID:
#menu li {
list-style-type: none;
width: 5em;
text-align: center;
margin-left: -2.5em;
}
width: 5em;
A group of buttons looks best if they're all the same size. Use the CSS width attribute to set each li to 5em.
margin-left: -2.5em;
Lists have a default indentation of about 2.5em to make room for the bullets or numbers. Because this list won't have bullets, it doesn't need the indentations. Overwrite the default indenting behavior by setting margin-left to a negative value.
#menu a {
text-decoration: none;
color: black;
display: block;
background-color: #EEEEFF;
box-shadow: 5px 5px 5px gray;
margin-bottom: 2px;
}
The button's appearance will make it clear that users can click it, so this is one place you can remove the underlining that normally goes with links.
box-shadow: 5px 5px 5px gray;
The shadow makes it look like a 3D button sticking out from the page. This is best attached to the anchor, so you can swap the border when the mouse is hovering over the button.
This is a sneaky trick. Block display normally makes an element act like a block-level element inside its container. In the case of an anchor, the entire button becomes clickable, not just the text. This makes your page easier to use because the mouse has a much bigger target to aim for:
display: block;
Use the margin-bottom rule to separate each button. This will enhance the 3D effect by making the shadows more obvious.
margin-bottom: 2px;
Use of the border-radius property gives the corners a nice rounded effect, enhancing the button feel.
Setting the border to outset can give the buttons just a bit more 3D appeal.
#menu a:hover {
background-color: #DDDDEE;
box-shadow: 3px 3px 3px gray;
border: none;
}
When the mouse hovers on the button, the shadow is smaller, and the background color of the element is darker. I also removed the border, making the button feel flat. These techniques together give a convincing illusion of the button being depressed.
This list makes an ideal navigation menu, especially when placed inside one column of a multicolumn floating layout.
Sometimes, you want horizontal button bars. Because HTML lists tend to be vertical, you might be tempted to think that a horizontal list is impossible. In fact, CSS provides all you need to convert exactly the same HTML to a horizontal list. Figure 3-2 shows such a page.
There's no need to show the HTML again because it hasn't changed at all. (Ain't CSS grand?) Even the CSS hasn't changed much:
#menu ul {
margin-left: -2.5em;
}
#menu li {
list-style-type: none;
width: 7em;
text-align: center;
float: left;
}
#menu a {
text-decoration: none;
color: black;
display: block;
background-color: #EEEEFF;
box-shadow: 5px 5px 5px gray;
margin-bottom: 2px;
margin-right: 2px;
border-radius: 5px;
border: 3px outset #EEEEFF;
}
#menu a:hover {
background-color: #DDDDEE;
box-shadow: 3px 3px 3px gray;
border: none;
}
The modifications are incredibly simple:
#menu li {
list-style-type: none;
float: left;
width: 5em;
text-align: center;
}
#menu ul {
margin-left: -2.5em;
}
Now that the button bar is horizontal, add a little space to the right of each button so they don't look so crowded together:
margin-right: 2px;
A simple list of buttons can look better than ordinary HTML links, but sometimes, your page needs to have a more complex navigation scheme. For example, you may want to create a menu system to help the user see the structure of your site.
When you think of a complex hierarchical organization (which is how most multipage websites end up), the easiest way to describe the structure is in a set of nested lists. HTML lists can contain other lists, and this can be a great way to organize data.
Nested lists are a great way to organize a lot of information, but they can be complicated. You can use some special tricks to make parts of your list appear and disappear when needed. In the sections “Hiding the inner lists” and “Getting the inner lists to appear on cue,” later in this chapter, you expand this technique to build a menu system for your pages.
Begin by creating a system of nested lists without any CSS at all. Figure 3-3 shows a page with a basic nested list.
No CSS styling is in place yet, but the list has its own complexities:
Here is the code for the nested list in plain HTML:
<!DOCTYPE html>
<html lang = "en-US">
<head>
<meta charset = "UTF-8">
<title>nestedList.html</title>
</head>
<body>
<h1>Some of my favorite links</h1>
<ul>
<li>Social networking
<ul>
<li><a href = "http://www.digg.com">digg</a></li>
<li><a href = "http://www.reddit.com">reddit</a></li>
<li><a href = "http://www.stumbleupon.com">stumbleupon</a></li>
</ul>
</li>
<li>Reference
<ul>
<li><a href = "http://www.google.com">google</a></li>
<li><a href = "http://wikipedia.org">wikipedia</a></li>
<li><a href = "http://dictionary.com">dictionary</a></li>
</ul>
</li>
<li>Web development
<ul>
<li>XHTML/CSS
<ul>
<li><a href = "http://www.w3schools.com">w3 schools</a></li>
<li><a href = "http://htmlhelp.com">htmlHelp</a></li>
<li><a href = "http://www.csszengarden.com">CSS Zen Garden</a></li>
</ul>
</li>
<li>Programming
<ul>
<li><a href = "http://javascript.com">javascript.com</a></li>
<li><a href = "http://php.net">php.net</a></li>
<li><a href = "http://www.mysql.com">mysql.com</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</body>
</html>
The first step of creating a dynamic menu system is to hide any lists that are embedded in a list item. Add the following CSS style to your page:
li ul {
display: none;
}
Your page will undergo a startling transformation, as shown in Figure 3-4.
That tiny little snippet of CSS code is a real powerhouse. It does some fascinating things, such as
This code works well on almost all browsers. It's pretty easy to make text disappear. Unfortunately, it's a little trickier to make all the browsers bring it back.
The fun part is getting the interior lists to pop up when the mouse is over the parent element. A second CSS style can make this happen:
li ul {
display: none;
}
li:hover ul {
display: block;
}
The new code is pretty interesting. When the page initially loads, it appears the same as what's shown in Figure 3-4, but see the effect of holding the mouse over the Social Networking element in Figure 3-5.
Here's how the list-reappearing code works:
This hide-and-seek trick isn't all that great on its own. It's actually quite annoying to have the contents pop up and go away like that. There's another more annoying problem. Look at Figure 3-6 to see what can go wrong.
To see why this happens, take another look at the CSS code that causes the segment to reappear:
li:hover ul {
display: block;
}
This code means set display to block for any ul that's a child of a hovered li. The problem is that the Web Development li contains a ul that contains two more uls. All the lists under Web Development appear, not just the immediate child.
One more modification of the CSS fixes this problem:
li ul {
display: none;
}
li:hover > ul {
display: block;
}
The greater than symbol (>) is a special selector tool. It indicates a direct relationship. In other words, the ul must be a direct child of the hovered li, not a grandchild or great-grandchild. With this indicator in place, the page acts correctly, as shown in Figure 3-7.
This trick allows you to create nested lists as deeply as you wish and to open any segment by hovering on its parent.
My current code has a list with three levels of nesting, but you can add as many nested lists as you want and use this code to make it act as a dynamic menu.
Figure 3-8 illustrates how to open the next section of the list.
You can combine the techniques of buttons and collapsing lists to build a menu system entirely with CSS. Figure 3-9 shows a page with a vertically arranged menu.
When the user hovers over a part of the menu, the related sub-elements appear, as shown in Figure 3-10.
This type of menu has a couple interesting advantages, such as
The vertical menu system works with exactly the same HTML as the hiddenList example — only the CSS changed. Here's the new CSS file:
/* vertMenu.css */
/* unindent entire list */
#menu ul {
margin-left: -2.5em;
}
/* set li as buttons */
#menu li {
list-style-type: none;
border: 1px black solid;;
width: 10em;
background-color: #cccccc;
text-align: center;
}
/* display anchors as buttons */
#menu a {
color: black;
text-decoration: none;
display: block;
}
/* flash white on anchor hover */
#menu a:hover {
background-color: white;
}
/* collapse menus */
#menu li ul {
display: none;
}
/* show submenus on hover */
#menu li:hover > ul {
display: block;
margin-left: -2em;
}
Of course, the CSS uses a few tricks, but there's really nothing new. It's just a combination of techniques you already know:
Because you're removing the list-style types, the normal indentation of list items will become a problem.
Each li tag inside the menu structure should look something like a button. Use CSS to accomplish this task:
/* set li as buttons */
#menu li {
list-style-type: none;
border: 1px black solid;
width: 10em;
background-color: #cccccc;
text-align: center;
}
/* display anchors as buttons */
#menu a {
color: black;
text-decoration: none;
display: block;
}
/* flash white on anchor hover */
#menu a:hover {
background-color: white;
}
Because the anchors no longer look like anchors, you have to do something else to indicate there's something special about these elements. When the user moves the mouse over any anchor tag in the menu div, that anchor's background color will switch to white.
/* collapse menus */
#menu li ul {
display: none;
}
/* show submenus on hover */
#menu li:hover > ul {
display: block;
margin-left: -2em;
}
You can make a variation of the menu structure that will work along the top of a page. Figure 3-11 shows how this might look.
The submenus come straight down from their parent elements. I find a little bit of indentation helpful for deeply nested lists, as shown in Figure 3-12.
Again, the HTML is identical. The CSS for a horizontal menu is surprisingly close to the vertical menu. The primary difference is floating the list items:
/* vertMenu.css */
/* unindent each unordered list */
#menu ul {
margin-left: -2.5em;
}
/* turn each list item into a solid gray block */
#menu li {
list-style-type: none;
border: black solid 1px;
float: left;
width: 10em;
background-color: #CCCCCC;
text-align: center;
}
/* set anchors to act like buttons */
#menu a {
display: block;
color: black;
text-decoration: none;
}
/* flash anchor white when hovered */
#menu a:hover {
background-color: white;
}
/* collapse nested lists */
#menu li ul {
display: none;
}
/* display sublists on hover */
#menu li:hover > ul {
display: block;
}
/* indent third-generation lists */
#menu li li li{
margin-left: 1em;
}
The CSS code has just a few variations from the vertical menu CSS:
/* turn each list item into a solid gray block */
#menu li {
list-style-type: none;
border: black solid 1px;
float: left;
width: 10em;
background-color: #CCCCCC;
text-align: center;
}
This causes the list items to appear next to each other in the same line.
A list nested deeper than its parent is hard to read. A little indentation helps a lot with clarity.
/* indent third-generation lists */
#menu li li li{
margin-left: 1em;
}
This selector is active on an element which has #menu and three list items in its family tree. It will work only on list items three levels deep. This special formatting isn't needed at the other levels but is helpful to offset the third-level list items.
These tricks are just the beginning of what you can do with some creativity and the amazing power of CSS and HTML. You can adopt the simple examples presented here to create your own marvels of navigation.