CSS Tutorial
CSS Project: Site Navbar
A horizontal nav with a brand, links, and a current-page style. It wraps cleanly on a narrow viewport.
What you will build
The top bar for Harbor studio. On the left, the brand. On the right, four links: Studio, Menu, Workshops, Visit. The current page is marked with a class, not with a different tag. On a narrow viewport the bar wraps instead of overflowing off the screen.
Use a real <nav> and a list of links. CSS turns that list into a row. A media query changes alignment and padding when the window is tight — it does not replace the landmarks.
Open an example with Try it in CSS. That loads /css/try — a live page preview.
Properties you will use
| Property | Job on this page |
|---|---|
display: flex | Brand on one side, links on the other |
justify-content / gap | Space inside the bar and between links |
list-style | Removes bullets so the nav reads as a bar |
.current color and border | Marks the page you are on |
@media | Wraps the bar and stacks links when the viewport is narrow |
Flex-wrap is the first safety net. The media query is the second: extra padding, smaller type, and a full-width link row.
Build in slices
First the bar as a flex row. Brand is a strong link. The list is horizontal.
Example
<style>
body { margin: 0; font-family: system-ui, sans-serif; }
.bar {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 0.75rem 1.25rem;
padding: 0.85rem 1.2rem;
background: #0c4a6e;
color: #e0f2fe;
}
.brand { color: #fff; text-decoration: none; font-weight: 800; font-size: 1.1rem; }
.links {
display: flex;
flex-wrap: wrap;
gap: 0.35rem 1rem;
margin: 0;
padding: 0;
list-style: none;
}
.links a { color: #e0f2fe; text-decoration: none; }
</style>
<header class="bar">
<a class="brand" href="#top">Harbor studio</a>
<nav aria-label="Site">
<ul class="links">
<li><a href="#studio">Studio</a></li>
<li><a href="#menu">Menu</a></li>
<li><a href="#workshops">Workshops</a></li>
<li><a href="#visit">Visit</a></li>
</ul>
</nav>
</header>Then mark the current link and add a wrap rule. Under 36 rem the bar becomes a stack: brand, then links.
Example
<style>
.links a:hover { color: #fff; }
.links a.current {
color: #fff;
border-bottom: 2px solid #38bdf8;
padding-bottom: 0.12rem;
}
.links a:focus-visible {
outline: 2px solid #7dd3fc;
outline-offset: 3px;
}
@media (max-width: 36rem) {
.bar { justify-content: center; text-align: center; }
.links { justify-content: center; width: 100%; }
}
</style>Narrow the preview at /css/try until the links wrap. If a link disappears off the right edge, flex-wrap is missing.
Complete page
A full Harbor studio page with the bar, a current-page style on Studio, and a short main so you can see the bar against page content. Hash links stay on the page so the preview does not 404.
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Harbor studio — site nav</title>
<style>
* { box-sizing: border-box; }
body {
margin: 0;
font-family: system-ui, sans-serif;
background: #e0f2fe;
color: #0c4a6e;
}
.bar {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 0.75rem 1.25rem;
padding: 0.85rem 1.25rem;
background: #0c4a6e;
color: #e0f2fe;
}
.brand {
color: #fff;
text-decoration: none;
font-weight: 800;
font-size: 1.15rem;
}
.links {
display: flex;
flex-wrap: wrap;
gap: 0.4rem 1.05rem;
margin: 0;
padding: 0;
list-style: none;
}
.links a {
color: #e0f2fe;
text-decoration: none;
font-weight: 600;
}
.links a:hover { color: #fff; }
.links a.current {
color: #fff;
border-bottom: 2px solid #38bdf8;
padding-bottom: 0.12rem;
}
.links a:focus-visible {
outline: 2px solid #7dd3fc;
outline-offset: 3px;
}
main {
max-width: 40rem;
margin: 0 auto;
padding: 1.6rem 1.25rem 2rem;
}
h1 { margin: 0 0 0.5rem; }
@media (max-width: 36rem) {
.bar { justify-content: center; text-align: center; }
.links { justify-content: center; width: 100%; }
}
</style>
</head>
<body>
<header class="bar">
<a class="brand" href="#top">Harbor studio</a>
<nav aria-label="Site">
<ul class="links">
<li><a class="current" href="#studio" aria-current="page">Studio</a></li>
<li><a href="#menu">Menu</a></li>
<li><a href="#workshops">Workshops</a></li>
<li><a href="#visit">Visit</a></li>
</ul>
</nav>
</header>
<main id="top">
<h1 id="studio">Open 8–16 by the pier</h1>
<p>Menus, workshop passes, and visiting hours live in this bar. On a phone the links wrap under the brand instead of sliding off the page.</p>
<h2 id="menu">Menu</h2>
<p>Sourdough, tomato, olive oil. Espresso until the last print comes off the press.</p>
<h2 id="workshops">Workshops</h2>
<p>Weekday, Harbor, and Season passes. The bar stays the same on every page.</p>
<h2 id="visit">Visit</h2>
<p>Chart Room door, Pier 2. Step through to the cafe if the studio bell is on quiet.</p>
</main>
</body>
</html>Practice tasks
- Move
currentandaria-currentto Menu. The underline should follow. - Add a fifth link named Hours. Check that the bar still wraps at /css/try.
- Raise the media breakpoint to
48remand decide whether the stack starts too early.