What You'll Build

In this tutorial, you'll build a fully responsive navigation bar from scratch using only HTML and CSS — no JavaScript required for the basic version. The result will be a horizontal nav on desktop that collapses into a mobile-friendly layout on smaller screens.

Prerequisites

  • Basic understanding of HTML structure
  • Familiarity with CSS (selectors, box model, basic properties)
  • A code editor (VS Code recommended)

Step 1: Set Up the HTML Structure

Start with semantic HTML. The <nav> element is the correct container for site navigation:

<nav class="navbar">
  <div class="nav-brand">
    <a href="/">YourSite</a>
  </div>
  <ul class="nav-links">
    <li><a href="/">Home</a></li>
    <li><a href="/about">About</a></li>
    <li><a href="/articles">Articles</a></li>
    <li><a href="/contact">Contact</a></li>
  </ul>
</nav>

Step 2: Base Styles

Style the navbar container and remove default list styles:

.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 2rem;
  background-color: #0F172A;
}

.nav-brand a {
  color: #E2E8F0;
  font-size: 1.25rem;
  font-weight: 700;
  text-decoration: none;
}

.nav-links {
  display: flex;
  list-style: none;
  gap: 2rem;
  margin: 0;
  padding: 0;
}

.nav-links a {
  color: #E2E8F0;
  text-decoration: none;
  font-size: 0.95rem;
  transition: color 0.2s;
}

.nav-links a:hover {
  color: #F59E0B;
}

Step 3: Add a Mobile Toggle (CSS-Only Checkbox Trick)

For a no-JavaScript mobile menu, use the checkbox hack. Add a hidden checkbox and a label to your HTML, just inside the <nav>:

<input type="checkbox" id="nav-toggle" class="nav-toggle">
<label for="nav-toggle" class="nav-toggle-label">
  <span></span>
</label>

Step 4: Responsive CSS with Media Queries

Add responsive styles that stack the nav links vertically on small screens:

.nav-toggle { display: none; }

.nav-toggle-label {
  display: none;
  cursor: pointer;
  flex-direction: column;
  gap: 5px;
}

.nav-toggle-label span,
.nav-toggle-label span::before,
.nav-toggle-label span::after {
  display: block;
  width: 25px;
  height: 3px;
  background: #E2E8F0;
  border-radius: 3px;
}

@media (max-width: 768px) {
  .nav-toggle-label { display: flex; }

  .nav-links {
    display: none;
    flex-direction: column;
    width: 100%;
    padding: 1rem 0;
    gap: 0.5rem;
  }

  .nav-toggle:checked ~ .nav-links {
    display: flex;
  }

  .navbar {
    flex-wrap: wrap;
  }
}

Step 5: Active State Styling

Highlight the current page link by adding an active class to the matching <a> tag and styling it:

.nav-links a.active {
  color: #F59E0B;
  font-weight: 600;
  border-bottom: 2px solid #F59E0B;
}

Next Steps & Enhancements

Once you have the basic version working, consider these improvements:

  1. Dropdown menus: Use :hover on a parent <li> to reveal a submenu
  2. Sticky navbar: Add position: sticky; top: 0; z-index: 100; to the nav
  3. Scroll effect: Use a small JavaScript snippet to add a shadow class after the user scrolls down
  4. Smooth transitions: Animate the mobile menu opening with max-height transitions

Building from scratch is the best way to understand how navigation systems work before reaching for a framework or component library. Once you've done it manually, you'll better appreciate — and customize — pre-built solutions.