CSS project 2a, turning a list of links into a horizontal menu
At the end of the last lesson the header band looked right, but the menu was still a bulleted list running down the page. This lesson turns it into a row of links. The HTML does not change. Here is the part we are working on:
<nav class="main-nav" aria-label="Main">
<ul class="menu">
<li><a href="index.html" aria-current="page">Home</a></li>
<li><a href="guides.html">Guides</a></li>
<li><a href="tools.html">Tools</a></li>
<li><a href="contact.html">Contact</a></li>
</ul>
</nav>
Keeping the menu as a list is the right call even though it will not look like one. Screen readers announce a list along with the number of items in it, which tells a listener how big the menu is before they hear any of it.
Five steps to a row
Add these two rules to style.css, below the ones you already have:
.menu {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 0;
padding: 0;
list-style: none;
}
.menu a {
display: block;
padding: 8px 12px;
border-radius: 4px;
}
Here is what each part does, in the order you would notice it:
- Remove the bullets.
list-style: nonehides the markers. The list is still a list in the HTML; it just stops looking like one. - Remove the default spacing. Browsers give a
<ul>a margin above and below and about 40 pixels of padding on the left, to make room for the bullets.margin: 0andpadding: 0remove both, so the menu no longer sits indented under the logo. - Line the items up.
display: flexturns the<ul>into a flex container. Its direct children, the four<li>elements, become flex items and sit side by side in a row. Note that the flex items are the list items, not the links inside them. - Space them out.
gap: 8pxputs 8 pixels between neighboring items and nothing before the first or after the last.flex-wrap: wraplets the row break onto a second line when the window is too narrow, instead of squeezing the links or running off the edge. - Give each link a real box. A link is inline by default, and vertical padding on an inline box does not push the lines around it away (the display lesson covers inline and block boxes).
display: blockmakes the link fill its list item, so the padding counts and the whole padded area is clickable. That bigger target matters on a phone, where a finger is much less precise than a mouse pointer. Theborder-radiushas nothing visible to round yet; it comes into play when the hover background arrives in lesson 19.
Save, reload, and the four links now sit in a row under the site name, still underlined, still white.
The older way: inline-block
Before flexbox worked everywhere, menus were built with floats (covered in the float lesson) or with inline-block. The inline-block version looks simple:
/* older approach, shown for reference */
.menu {
list-style: none;
margin: 0;
padding: 0;
}
.menu li {
display: inline-block;
margin-right: 8px;
}
An inline-block element sits in a line of text like a word, but accepts width, height and vertical padding like a block. Set the list items to inline-block and they flow along one line.
The catch is that they really do behave like words. The line break and indentation between </li> and the next <li> in your HTML count as a space, so the browser adds a gap of roughly a space character between items on top of your margin. The gap changes with the font size, and it shows up in measurements as a few mystery pixels. The usual workarounds were ugly: deleting the whitespace from the HTML, writing <!-- --> comments between items, or setting font-size: 0 on the list and restoring it on the items. Items also line up on the text baseline, which can leave them slightly out of line when they hold different content.
A flex container ignores whitespace between its items and stretches them to the same height, so none of that comes up. The inline-block approach does have one thing going for it, which the next lesson uses: since the items are inline, text-align on the list moves them around.
Try it
Paste the project HTML into the online HTML editor, swap the <link> line for a <style> element holding everything in style.css so far, and add the two new rules. Then change gap to 24px, and remove flex-wrap: wrap and narrow the window to see the links squeeze together instead of wrapping.