CSS Tutorial
CSS Navigation
A nav bar is a flex list of links. Hover, current page, and a small-screen wrap or menu.
A list of links, laid out
Site navigation is HTML first: a nav, usually a ul of a elements. CSS then removes the bullets, puts the items in a row, and marks the current page. Harbor studio’s bar is Home, Desks, Hours, Visit — four links, flex, a teal current state, and a wrap when the preview is narrow.
You do not need a hamburger to learn this chapter. A wrapping flex nav is honest on a small screen and still keyboard-friendly. A disclosure menu is a later pattern, with more JavaScript than this tutorial wants to sneak in.
Flex the list
Reset list padding and bullets. Set the ul to display: flex with gapand flex-wrap: wrap. Style the anchors as blocks with padding so the hit area is larger than the word.
Example
<style>
body {
font-family: system-ui, sans-serif;
color: #0c4a6e;
background: #f0f9ff;
margin: 1.25rem;
}
nav {
background: #fff;
border: 1px solid #7dd3fc;
border-radius: 0.55rem;
padding: 0.4rem 0.6rem;
}
nav ul {
display: flex;
flex-wrap: wrap;
gap: 0.25rem 0.35rem;
list-style: none;
margin: 0;
padding: 0;
}
nav a {
display: block;
padding: 0.45rem 0.75rem;
border-radius: 0.35rem;
color: #0369a1;
text-decoration: none;
font-weight: 650;
}
nav a:hover {
background: #e0f2fe;
color: #0c4a6e;
}
</style>
<h1>Harbor studio</h1>
<nav aria-label="Studio">
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">Desks</a></li>
<li><a href="#">Hours</a></li>
<li><a href="#">Visit</a></li>
</ul>
</nav>list-style: none removes bullets. Some screen readers then skip announcing the list unless the ul keeps its list role — in practice, keep the ul/li markup and do not replace it with bare links in a div. Open this bar at /css/try.
Hover, focus, and the current page
Hover is a hint. The current page is information. Use a class on the current link (your HTML or a small template sets it) rather than hoping the URL matches. Focus needs a ring, especially after you restyle anchors to look like pills.
| State | What to show |
|---|---|
| Default | Readable color on the bar background |
:hover | A light sky fill, still a link, not a new layout |
:focus-visible | A 3px outline with offset |
.current (or aria-current="page") | Teal fill, white text, so “you are here” is obvious |
Example
<style>
body {
font-family: system-ui, sans-serif;
color: #0c4a6e;
background: #f0f9ff;
margin: 1.25rem;
}
nav ul {
display: flex;
flex-wrap: wrap;
gap: 0.3rem;
list-style: none;
margin: 0;
padding: 0;
}
nav a {
display: block;
padding: 0.45rem 0.8rem;
border-radius: 999px;
color: #0369a1;
text-decoration: none;
font-weight: 650;
}
nav a:hover { background: #e0f2fe; }
nav a:focus-visible {
outline: 3px solid #0d9488;
outline-offset: 2px;
}
nav a[aria-current="page"] {
background: #0d9488;
color: #fff;
}
</style>
<nav aria-label="Studio">
<ul>
<li><a href="#" aria-current="page">Desks</a></li>
<li><a href="#">Hours</a></li>
<li><a href="#">Visit</a></li>
</ul>
</nav>aria-current="page" is both a style hook and an accessibility name for the current item. Prefer it over a class that only CSS knows about, or pair the two.
A bar that wraps on small screens
Put the brand and the list in one flex row with justify-content: space-between andflex-wrap: wrap. When the viewport is tight, the links drop under the name instead of overflowing. That is often enough. A min-width query can switch the list to a column with full-width hit targets if the labels are long.
Example
<style>
body {
font-family: system-ui, sans-serif;
color: #0c4a6e;
background: #f0f9ff;
margin: 1.25rem;
}
.bar {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
gap: 0.5rem 1rem;
padding: 0.55rem 0.75rem;
background: #fff;
border: 1px solid #bae6fd;
border-radius: 0.6rem;
}
.brand {
margin: 0;
font-size: 1.05rem;
color: #0d9488;
}
.bar ul {
display: flex;
flex-wrap: wrap;
gap: 0.2rem;
list-style: none;
margin: 0;
padding: 0;
}
.bar a {
display: block;
padding: 0.4rem 0.7rem;
border-radius: 0.35rem;
color: #0284c7;
text-decoration: none;
font-weight: 650;
}
.bar a:hover { background: #e0f2fe; }
.bar a[aria-current="page"] {
background: #0d9488;
color: #fff;
}
@media (min-width: 40rem) {
.bar a { padding: 0.45rem 0.85rem; }
}
</style>
<header class="bar">
<p class="brand">Harbor studio</p>
<nav aria-label="Studio">
<ul>
<li><a href="#">Home</a></li>
<li><a href="#" aria-current="page">Desks</a></li>
<li><a href="#">Hours</a></li>
<li><a href="#">Visit</a></li>
</ul>
</nav>
</header>Skip hover-only flyout menus as the only way to reach a section. If you add a collapsed menu later, the same links must remain in the DOM and focusable when open. For this chapter, wrap and current page are the whole job.
Worked examples
The short listings above show one property. These sheets paint documents you would actually ship: a lab dashboard, a clinic form, a marks table, a nav bar.
CSS does not invent meaning. HTML already said what the pieces are. Cascade, specificity, and the box model decide how they look. The numbers are classroom values — current, pH, pulse, 3-4-5 — so the style has something real to sit on.
Preview them in the CSS editor at /css/try. Change one property and watch the page paint. The tags stay the same.
Engineering
A lab nav as a flex list
nav > a in a flex row is a bar. gap replaces margin hacks. flex-wrap lets links fall on a phone instead of overflowing.
The current page needs a class or [aria-current="page"] so colour is not the only cue. Hover is extra.
Example
<style>
nav { display: flex; flex-wrap: wrap; gap: 0.6rem; background: #f0fdfa; padding: 0.5rem; }
a { color: #0f766e; text-decoration: none; }
a[aria-current="page"] { font-weight: 700; text-decoration: underline; }
</style>
<nav>
<a href="/css" aria-current="page">Lab home</a>
<a href="/css/flexbox">Flex</a>
<a href="/css/grid">Grid</a>
</nav>Biology
Clinic links that wrap
A wrapping nav is better than a hamburger you have not built yet. Padding on each a makes the hit target at least 44 px class in later work.
Example
<style>
nav { display: flex; flex-wrap: wrap; gap: 0.4rem; }
a { background: #fef3c7; color: #9f1239; padding: 0.35rem 0.6rem; text-decoration: none; }
</style>
<nav>
<a href="/css">Home</a>
<a href="/css/forms">Book</a>
<a href="/css/text">Advice</a>
</nav>