WDD10 - CSS: horizontal navigation bar and descendant selectors
- I can remove default list styling and use float to turn a bulleted list into a horizontal navigation bar.
- I can use descendant selectors consistently to scope every nav bar rule to only the navigation, not every list and link on the page.
- I can use the :hover pseudo-class to add a visual state change when the mouse is over a link.
- I can list, in order, the five CSS rules that turn a plain list into a horizontal navigation bar.
- I can explain why nav ul / nav li / nav a are used instead of ul / li / a.
- I can identify a missing step in a broken navigation bar build and fix it.
WDD10 reuses the descendant selector from WDD6 and the float property from WDD7 - both return today.
Key vocabulary
From vertical list to horizontal bar
A navigation bar starts as an ordinary list
The standard way to mark up a set of navigation links in HTML is a plain unordered list: a <ul> containing one <li> per link, each holding an <a>. By default this renders as a vertical, bulleted list - not remotely like the horizontal navigation bars seen across almost every website. Turning this ordinary list into a navigation bar is a specific, repeatable five-step CSS build, and every one of the five rules is written using a descendant selector that starts from nav, so the rules only affect this particular list, not every list on the page.
The five steps, in order
Step 1 removes the browser's default bullet points with list-style: none; on nav ul, and typically adds a background colour at the same time. Step 2 applies float: left; to nav li, pulling the list items out of normal flow and into a horizontal row instead of a vertical stack. Step 3 gives each floated nav li a fixed width, so every item in the row lines up evenly rather than being sized to its own text. Step 4 is easy to forget: setting display: block; (plus padding) on nav a, because a default inline <a> is only as clickable as its text - display: block expands the clickable area to fill the whole padded box. Step 5 adds nav a:hover with a different background or colour, giving a visible cue that the link is interactive.
nav ul { list-style: none; background: #042C53; }nav li { float: left; }nav li { width: 120px; }nav a { display: block; padding: 14px; }nav a:hover { background: #185FA5; }Working nav bar ✓Live example above, built with the five rules from the pipeline - hover over a link to see step 5 in action.
Why every rule uses a descendant selector
WDD6 introduced the descendant selector; WDD10 is the lesson where it becomes essential rather than optional. If step 1 were written as a bare ul { list-style: none; } instead of nav ul { list-style: none; }, it would remove bullets from every list on the page, not just the navigation - including, for example, a bulleted list of features inside the page's main content. Scoping every rule with nav as the ancestor keeps the whole five-step build isolated to the navigation bar alone, which is exactly why descendant selectors matter here rather than just being a syntax alternative to global element selectors.
list-style: none;
Worked examples
nav ul { list-style: none; background: #042C53; }
nav li { float: left; width: 120px; }
nav a { display: block; padding: 14px; color: white; text-decoration: none; }
nav a:hover { background: #185FA5; }
padding: 14px;
The padding is added, but only the text itself responds to clicks and hover - clicking beside the word does nothing.
padding: 14px;
The whole padded rectangle becomes clickable and responds to :hover, not just the text.
<nav>
<ul><li><a href="#">Home</a></li></ul>
</nav>
<section>
<ul><li>Feature one</li></ul>
</section>
<ul> elements.nav li { float: left; } only matches <li> elements that sit inside <nav>, at any depth.A pupil writes nav li { float: left; width: 100px; } but forgets to add any rule for nav a at all. The links still float into a row, but clicking anywhere except directly on the text does nothing. Which step is missing?
Steps 1-3 (remove bullets, float, even width) are all present and working - the row layout is correct.
Step 4 is missing: nav a { display: block; padding: ...; }. Without it, the default inline <a> only responds to clicks on its own text, not the full 100px-wide box around it.
Missing step: display: block on nav a.
Practical: build a navigation bar, WebStorm
Download the starter file below - a plain, default bulleted list wrapped in <nav>.
Download WDD10_starter.html- Add an internal stylesheet in
<head>. - Work through the five steps from the flow-pipeline above, saving and refreshing after each one.
- Use
nav ul,nav liandnav athroughout - not bareul,liora. - Check the paragraph below the navigation bar in the starter file still displays correctly once the list items are floated.
- Using bare ul, li, a selectors instead of nav ul, nav li, nav a. This applies every rule to all matching elements on the page, not just the navigation bar.
- Forgetting display: block on nav a. Without it, only the link's own text is clickable and hoverable, not the full padded box around it.
- Calling the descendant selector a "child selector." A descendant selector (nav a) matches at any depth inside the ancestor; a child selector (nav > a) only matches direct children - they are different, and Higher exam answers should use the correct term.
- Applying :hover to nav li instead of nav a. The interactive element pupils click is the link, so the hover state belongs on nav a for the colour change to align with the clickable area.
Use the exact term descendant selector when describing why nav ul, nav li and nav a are used - not "child selector," which names a different, narrower CSS selector. If asked to list the steps in building a navigation bar, name all five in order: remove bullets, float horizontal, set even widths, make links display: block, then add :hover.
Task Set A - Core questions
nav ul { list-style: none; }
nav li { float: left; width: 100px; }
nav a { color: white; }
nav ul { list-style: none; }
nav li { float: left; width: 100px; }
nav a { display: block; padding: 12px; color: white; }
nav a is missing display: block (and padding). Without it, the default inline link only responds to clicks on its own text, not the full 100px-wide floated box around it.
Task Set B - Extension
- In WebStorm, create a new HTML file called
nav-variant.html. - Add a
<nav>containing a<ul>of at least five<li><a>links. - Build all five steps yourself from memory, without looking at the earlier example - use a different background colour and item width to check you understand the pattern rather than just copying values.
- Save, open in a browser, and check the bar is horizontal, fully clickable across each item's width, and changes colour on hover.
nav ul {
list-style: none;
background: #712B13;
}
nav li {
float: left;
width: 110px;
}
nav a {
display: block;
padding: 12px;
color: white;
text-decoration: none;
text-align: center;
}
nav a:hover {
background: #D85A30;
}
Compare your own file against this rather than copying it - the exact colours and width do not matter, but all five rules (list-style, float, width, display: block, :hover) should be present and scoped with nav.
File this in OneNote under:
Higher Computing Science > Web Design & Development > WDD10
Timing risk: this lesson is scoped for a double period but is scheduled on a single (Tue 1 Dec 2026, per WDD.md §2a/§4 - one of the four flagged "too short" mismatches, along with WDD4, WDD7 and WDD16). Do not try to cover everything in class.
Suggested compressed timing (single period, ~50 min): 5 min warm up, 8 min five-step notes + flow-pipeline + live demo, 6 min descendant-selector-scoping notes + context box, 8 min Examples 2-3, remaining time on Task Set A questions A1-A6 only. Push A7-A9 and all of Task Set B, including the B3 WebStorm practical, to independent/homework time.
Scope control: deliberately does not cover flexbox or CSS Grid as alternative modern nav bar techniques - the SQA spec and Chris's own L9 both teach the float-based five-step build specifically, and flexbox is explicitly out of scope for this course (see CLAUDE.md WDD scope note).
Descendant selector terminology is the highest-value fact in this lesson for exam purposes - Chris's own materials use the incorrect term "child selector" for this pattern, and WDD6 already corrected this ahead of today. A3/A8/exam tip all reinforce the correct term and the practical consequence of getting scope wrong.