Skip to content

CSS Tutorial Practical Projects

Project: A Navigation Bar

Lesson 173 of 182 2 min read By Deepak Paswan Updated Oct 4, 2026

A navigation bar is the most common piece of page layout. We will build one with a logo on the left, links in the middle and a button on the right.

Start with the HTML

Navigation is a list of links, so use <nav> and a list.

index.html
HTML
<header class="site-header">
  <a class="logo" href="#">Juniper</a>
  <nav aria-label="Main">
    <ul class="menu">
      <li><a href="#" aria-current="page">Home</a></li>
      <li><a href="#">Shop</a></li>
      <li><a href="#">Journal</a></li>
      <li><a href="#">About</a></li>
    </ul>
  </nav>
  <a class="btn" href="#">Sign in</a>
</header>

The finished navigation bar

index.html
HTML
<style>
  *, *::before, *::after { box-sizing: border-box; }
  body { margin: 0; font-family: system-ui, sans-serif; }

  .site-header {
    position: sticky; top: 0;
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px 24px;
    padding: 12px 20px; background: #1a5276; color: #fff;
  }
  .logo { font-weight: 800; font-size: 1.25rem; color: #fff; text-decoration: none; margin-right: auto; }

  .menu { display: flex; flex-wrap: wrap; gap: 4px; list-style: none; margin: 0; padding: 0; }
  .menu a { display: block; padding: 8px 12px; color: #fff; text-decoration: none; border-radius: 6px; }
  .menu a:hover { background: rgba(255,255,255,.15); }
  .menu a[aria-current="page"] { background: rgba(255,255,255,.25); font-weight: 600; }
  .menu a:focus-visible, .btn:focus-visible, .logo:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }

  .btn { padding: 8px 18px; border-radius: 999px; background: #d94a00; color: #fff; text-decoration: none; font-weight: 600; }
  .btn:hover { background: #b84624; }

  /* Narrow: put the menu on its own full-width row */
  @media (max-width: 480px) {
    .site-header nav { order: 3; width: 100%; }
  }
  main { padding: 20px; height: 300px; }
</style>
<header class="site-header">
  <a class="logo" href="#">Juniper</a>
  <nav aria-label="Main">
    <ul class="menu">
      <li><a href="#" aria-current="page">Home</a></li>
      <li><a href="#">Shop</a></li>
      <li><a href="#">Journal</a></li>
      <li><a href="#">About</a></li>
    </ul>
  </nav>
  <a class="btn" href="#">Sign in</a>
</header>
<main><p>Scroll the Result panel: the header sticks to the top.</p></main>

How it works

  • .site-header is a flex container. margin-right: auto on the logo pushes the menu and button to the right.
  • flex-wrap: wrap keeps it from overflowing on small screens. The extra-narrow rule moves the menu to its own row with order: 3.
  • Links are display: block with padding, so the whole rectangle is clickable.
  • aria-current="page" marks the current page for screen readers, and the same attribute is used by CSS to style it. One source of truth.
  • position: sticky; top: 0 keeps the bar visible while scrolling.

Extensions

  1. Add a dropdown under “Shop” using :hover and :focus-within on the list item.
  2. Replace the narrow layout with a menu button. That needs a little JavaScript to toggle a class.
  3. Add scroll-margin-top to page sections so that anchor links are not hidden by the sticky bar.
warning
A sticky header that covers content
If anchor links jump to a heading and the bar hides it, give the target scroll-margin-top equal to the bar’s height.