Styling the Header and Navigation
The header is the first element a visitor sees on every page of the STO site. It sets the brand tone, orients users, and provides navigation. This lesson builds it to production quality — applying custom properties, Flexbox, responsive breakpoints, and hover/active states.
Site header structure
Section titled “Site header structure”The HTML structure the CSS targets:
<header class="site-header"> <div class="content-wrapper header-inner"> <a href="index.html" class="site-logo">Summit Trail Outfitters</a> <nav class="site-nav" aria-label="Main navigation"> <ul class="nav-links"> <li><a href="index.html">Home</a></li> <li><a href="tours.html">Tours</a></li> <li><a href="blog.html">Blog</a></li> <li><a href="about.html">About</a></li> <li><a href="contact.html">Contact</a></li> </ul> </nav> </div></header>Mobile-first header styles
Section titled “Mobile-first header styles”/* === Site Header === */
.site-header { background-color: var(--color-primary); box-shadow: var(--shadow-md); position: sticky; top: 0; z-index: 100;}
.header-inner { display: flex; flex-direction: column; padding: var(--space-md); gap: var(--space-sm);}
/* Tablet and above: logo left, nav right */@media (min-width: 768px) { .header-inner { flex-direction: row; justify-content: space-between; align-items: center; padding: var(--space-md) 0; }}position: sticky; top: 0 keeps the header at the top of the viewport as the user scrolls. z-index: 100 ensures it appears above all other content.
Logo treatment
Section titled “Logo treatment”.site-logo { font-family: var(--font-heading); font-size: 1.375rem; font-weight: 700; color: var(--color-bg); text-decoration: none; letter-spacing: -0.01em; line-height: 1;}
.site-logo:hover { color: var(--color-accent);}The heading font (Playfair Display) gives the logo a distinctive, brand-appropriate feel while matching the heading style used throughout the site.
Navigation links
Section titled “Navigation links”.nav-links { display: flex; flex-direction: column; gap: var(--space-xs);}
@media (min-width: 768px) { .nav-links { flex-direction: row; gap: var(--space-lg); align-items: center; }}
.nav-links a { color: var(--color-accent); text-decoration: none; font-weight: 600; font-size: 0.95rem; letter-spacing: 0.02em; text-transform: uppercase; padding: var(--space-xs) 0; border-bottom: 2px solid transparent; transition: color var(--transition-fast), border-color var(--transition-fast);}
.nav-links a:hover { color: var(--color-white); border-bottom-color: var(--color-accent);}The border-bottom: 2px solid transparent on the default state reserves space for the hover underline — preventing the layout from shifting when the border appears on hover.
Active link state
Section titled “Active link state”The active page link should be visually distinct so users always know where they are:
.nav-links a[aria-current="page"],.nav-links a.active { color: var(--color-white); border-bottom-color: var(--color-accent);}In your HTML, add aria-current="page" to the link that matches the current page:
<li><a href="tours.html" aria-current="page">Tours</a></li>aria-current="page" serves double duty: it is a CSS hook for the active style, and it communicates to screen readers that this is the current page — an accessibility win that costs nothing.
Mobile hamburger button
Section titled “Mobile hamburger button”A hamburger menu hides the nav links on mobile and reveals them when the user taps a button. The toggle behavior requires JavaScript — but the HTML and CSS live here, in the header.
First, add the button to every STO HTML file (index.html, about.html, tours.html, blog.html, blog-article.html, contact.html). Place it inside <div class="header-inner">, between the logo link and the <nav>:
<button class="hamburger-btn" aria-expanded="false" aria-label="Toggle navigation"> <span></span> <span></span> <span></span></button>The three <span> elements are the three lines of the icon. aria-expanded="false" tells screen readers the nav is currently closed — JavaScript will keep this in sync when the nav opens and closes.
The .header-inner needs to change from a column stack to a row so the logo and button sit side by side, with the nav wrapping below on its own line:
.header-inner { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: space-between; align-items: center; padding: var(--space-md); gap: var(--space-sm);}Then add the following after the active link state styles:
/* === Mobile Nav Toggle === */
.hamburger-btn { display: flex; flex-direction: column; gap: 5px; background: none; border: none; cursor: pointer; padding: var(--space-xs);}
.hamburger-btn span { display: block; width: 24px; height: 2px; background-color: var(--color-bg); border-radius: 2px;}
@media (min-width: 768px) { .hamburger-btn { display: none; }}
.site-nav { display: none; width: 100%;}
.site-nav.nav-open { display: block;}
@media (min-width: 768px) { .site-nav { display: block; width: auto; }}At mobile width, the hamburger button is now visible and the nav is hidden. The nav will not open yet — that requires the JavaScript you will write in JavaScript Foundations. At 768px and above, the button hides and the nav shows as normal.
Sticky header on scroll
Section titled “Sticky header on scroll”A sticky header adds visual weight as the page scrolls. Adding a subtle box-shadow enhancement when the header is stuck is a common pattern:
.site-header { position: sticky; top: 0; z-index: 100; transition: box-shadow var(--transition-normal);}The base box-shadow from var(--shadow-md) is already set — it provides depth against the page content that scrolls beneath.
Exercise
Section titled “Exercise”Apply the header and mobile nav styles to the STO site:
-
Add all header CSS to
styles.css, including the updated.header-inner,.hamburger-btn, and mobile nav toggle rules. -
Add the
<button class="hamburger-btn">to every STO HTML file inside.header-inner, between the logo and the<nav>. -
Update each HTML file to add
aria-current="page"to the correct nav link for that page. -
Open
index.htmlin Chrome at 375px (DevTools device toolbar). Confirm:- The hamburger button is visible in the top right of the header
- The nav links are hidden
- The logo and button sit on the same row
-
Widen to 768px. Confirm:
- The hamburger button disappears
- The nav links appear in a row to the right of the logo
-
Scroll down the page. The header should stay pinned to the top of the viewport.
-
Hover over a nav link and verify the color change and underline animation work.
- Use custom properties (
var(--color-primary), etc.) for all color values in the header — this keeps it consistent with the rest of the site and easy to update. position: sticky; top: 0; z-index: 100pins the header to the top of the viewport during scroll.flex-direction: row; flex-wrap: wrapon.header-innerlets the logo and hamburger button sit on one row, with the nav wrapping to a second row below on mobile.aria-current="page"on the active link provides both the CSS hook for the active style and accessibility information for screen readers.- Reserve border space in the default state to prevent layout shift on hover.
- The hamburger button and
.site-navhide/show CSS belong here — the toggle behavior requires JavaScript, but the HTML structure and visual states are a CSS concern.
Lesson 03 styles the homepage — the highest-impact page on the site, with a full-bleed hero, featured tour cards, and a call-to-action section.