Lab

Navigation Lab

Eight navigation patterns — from sticky blur nav to mobile hamburger menus and mega dropdowns.

1. Classic Horizontal — logo + links + CTA
<nav class="nav">
  <div class="logo">studio.</div>
  <ul class="links">
    <li><a href="#">Work</a></li>
    <li><a href="#">About</a></li>
    <li><a href="#">Journal</a></li>
    <li><a href="#">Contact</a></li>
  </ul>
  <a href="#" class="cta">Start project</a>
</nav>
.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 28px;
  border-bottom: 1px solid #eee;
}
.links {
  display: flex;
  gap: 28px;
  list-style: none;
}
.cta {
  padding: 8px 18px;
  border-radius: 999px;
  background: #111;
  color: #fff;
}
2. Sticky Blur — position: sticky + backdrop-filter on scroll

Scroll to see the blur in action

The nav stays pinned to the top and the blur picks up whatever colors sit behind it. Works especially well on colorful or image-heavy sites.

Keep scrolling — notice how the background fades as content slides under the bar.

<nav class="nav">
  <div class="logo">aurora</div>
  <ul class="links">
    <li><a href="#">Shop</a></li>
    <li><a href="#">Journal</a></li>
    <li><a href="#">Stores</a></li>
  </ul>
</nav>

<!-- content that scrolls underneath -->
<main>
  <h2>Scroll to see the blur in action</h2>
  <p>The nav stays pinned to the top and the blur picks up whatever colors sit behind it. Works especially well on colorful or image-heavy sites.</p>
  <p>Keep scrolling — notice how the background fades as content slides under the bar.</p>
</main>
/* Stays at the top while page scrolls */
.nav {
  position: sticky;
  top: 0;
  z-index: 2;
  background: rgba(255,255,255,.7);
  backdrop-filter: blur(16px) saturate(1.4);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  border-bottom: 1px solid rgba(255,255,255,.5);
}
3. Hamburger Menu — pure CSS checkbox hack, no JS
<!-- Hidden checkbox drives everything -->
<input type="checkbox" id="burger" class="burger-toggle">

<nav class="nav">
  <div class="logo">orbit</div>

  <!-- Label acts as the button -->
  <label for="burger" class="burger-btn">
    <span></span><span></span><span></span>
  </label>
</nav>

<div class="mobile-menu">
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="#">Features</a></li>
    <li><a href="#">Pricing</a></li>
    <li><a href="#">Contact</a></li>
  </ul>
</div>
/* Hide the actual checkbox */
.burger-toggle { display: none; }

/* Menu panel uses max-height for smooth open */
.mobile-menu {
  max-height: 0;
  overflow: hidden;
  transition: max-height .4s ease;
}

/* When checked, expand the menu */
.burger-toggle:checked ~ .mobile-menu {
  max-height: 300px;
}

/* Animate the 3 burger bars into an X */
.burger-toggle:checked ~ .nav span:nth-child(1) { transform: rotate(45deg); top: 9px; }
.burger-toggle:checked ~ .nav span:nth-child(2) { opacity: 0; }
.burger-toggle:checked ~ .nav span:nth-child(3) { transform: rotate(-45deg); top: 9px; }
// Prefer a real button + JS toggle for accessibility (announces state).
// Use this in place of the checkbox hack if you want screen readers
// to hear "expanded / collapsed" when the menu opens.
const btn  = document.querySelector('.burger-btn');
const menu = document.querySelector('.mobile-menu');

btn.addEventListener('click', () => {
  const open = menu.classList.toggle('open');
  btn.setAttribute('aria-expanded', open);
  btn.setAttribute('aria-label', open ? 'Close menu' : 'Open menu');
});

// Close the menu when any link inside it is clicked
menu.querySelectorAll('a').forEach(a => {
  a.addEventListener('click', () => {
    menu.classList.remove('open');
    btn.setAttribute('aria-expanded', 'false');
  });
});
4. Mega Menu — multi-column dropdown on hover

Hover "Shop" to reveal the mega menu ↑

<nav class="nav">
  <div class="logo">emporium</div>
  <ul class="links">
    <li class="drop">
      <a href="#">Shop ▾</a>
      <div class="mega">
        <div class="mega-col">
          <h4>Clothing</h4>
          <ul>
            <li><a href="#">Tops</a></li>
            <li><a href="#">Bottoms</a></li>
            <li><a href="#">Outerwear</a></li>
          </ul>
        </div>
        <div class="mega-col">
          <h4>Accessories</h4>
          <ul>
            <li><a href="#">Hats</a></li>
            <li><a href="#">Bags</a></li>
            <li><a href="#">Eyewear</a></li>
          </ul>
        </div>
      </div>
    </li>
    <li><a href="#">About</a></li>
    <li><a href="#">Contact</a></li>
  </ul>
</nav>
.drop { position: relative; }

.mega {
  position: absolute;
  top: calc(100% + 10px);
  width: 520px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  padding: 22px;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 12px 36px rgba(0,0,0,.08);
  opacity: 0;
  visibility: hidden;
  transition: all .2s;
}

.drop:hover .mega {
  opacity: 1;
  visibility: visible;
}
5. Sidebar Vertical — app-style navigation for dashboards

Dashboard

Your main content area goes here.

<div class="layout">
  <aside class="side">
    <div class="brand">moonbase</div>
    <ul>
      <li><a href="#">Home</a></li>
      <li class="active"><a href="#">Dashboard</a></li>
      <li><a href="#">Projects</a></li>
      <li><a href="#">Team</a></li>
      <li><a href="#">Messages</a></li>
      <li><a href="#">Settings</a></li>
    </ul>
  </aside>

  <main class="panel">
    <h3>Dashboard</h3>
    <p>Your main content area goes here.</p>
  </main>
</div>
/* Two-column grid for sidebar + main */
.layout {
  display: grid;
  grid-template-columns: 220px 1fr;
}

.side {
  background: #0f172a;
  color: #cbd5e1;
  padding: 24px 16px;
}

.side li a {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border-radius: 8px;
}

.side li.active a {
  background: rgba(236,72,153,.15);
  color: #fbcfe8;
}
6. Breadcrumbs — slash, arrow, and pill styles (pick one)

Slash style

Arrow style

Pill style

<!-- Slash style -->
<ul class="bc">
  <li><a href="#">Home</a></li>
  <li><a href="#">Labs</a></li>
  <li><a href="#">Gallery</a></li>
  <li class="current">Masonry</li>
</ul>

<!-- Arrow style -->
<ul class="bc arrows">
  <li><a href="#">Shop</a></li>
  <li><a href="#">Men</a></li>
  <li><a href="#">Shoes</a></li>
  <li class="current">Runners</li>
</ul>

<!-- Pill style -->
<ul class="bc pills">
  <li><a href="#">Docs</a></li>
  <li><a href="#">Components</a></li>
  <li class="current">Button</li>
</ul>
.bc {
  display: flex;
  gap: 8px;
  list-style: none;
  color: #666;
}

/* The separator comes from ::before on 2nd+ items */
.bc li + li::before {
  content: "/";
  color: #ccc;
  margin-right: 8px;
}

.bc.arrows li + li::before { content: "›"; }

.bc.pills li {
  background: #f4f4f5;
  padding: 4px 12px;
  border-radius: 999px;
}

.bc .current {
  color: #111;
  font-weight: 600;
}
7. Bottom Tab Bar — mobile app style floating nav
Preview content
<nav class="tabbar">
  <button><i class="ph ph-house"></i>Home</button>
  <button class="active"><i class="ph-fill ph-magnifying-glass"></i>Search</button>
  <button><i class="ph ph-bell"></i>Alerts</button>
  <button><i class="ph ph-user-circle"></i>Profile</button>
</nav>
.tabbar {
  position: fixed; /* or absolute in a container */
  bottom: 14px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 4px;
  background: #fff;
  padding: 8px;
  border-radius: 999px;
  box-shadow: 0 10px 30px rgba(0,0,0,.12);
}

.tabbar button {
  display: flex;
  flex-direction: column;
  padding: 8px 16px;
  border-radius: 999px;
}

.tabbar .active {
  background: linear-gradient(135deg, #ec4899, #8b5cf6);
  color: #fff;
}
// Tap any tab to make it the active one
const buttons = document.querySelectorAll('.tabbar button');

buttons.forEach(btn => {
  btn.addEventListener('click', () => {
    buttons.forEach(b => b.classList.remove('active'));
    btn.classList.add('active');
  });
});
8. Pill Nav — floating capsule nav over a colorful background
<nav class="pill-nav">
  <a href="#" class="active">Home</a>
  <a href="#">Catalog</a>
  <a href="#">Blog</a>
  <a href="#">Pricing</a>
  <a href="#">Contact</a>
</nav>
.pill-nav {
  display: inline-flex;
  padding: 6px;
  gap: 4px;
  background: rgba(255,255,255,.6);
  backdrop-filter: blur(10px);
  border-radius: 999px;
}

.pill-nav a {
  padding: 8px 18px;
  border-radius: 999px;
  font-weight: 600;
  text-decoration: none;
  color: #555;
}

.pill-nav a.active {
  background: #111;
  color: #fff;
}
Copy & Paste

A complete, working navbar

The patterns above are trimmed previews. This block is the whole thing — a responsive top navbar that collapses to a tap-to-open menu on phones. Paste the HTML at the top of your <body>, the CSS into your stylesheet, and the JS before </body>. No libraries needed.

1. HTML — paste at the top of your <body>

<nav class="site-nav" aria-label="Main">
  <a class="sn-logo" href="index.html">Brandr</a>
  <button class="sn-toggle" aria-label="Open menu" aria-expanded="false">&#9776;</button>
  <ul class="sn-links">
    <li><a href="#">Home</a></li>
    <li><a href="#">Features</a></li>
    <li><a href="#">Pricing</a></li>
    <li><a href="#">About</a></li>
  </ul>
</nav>

2. CSS — paste into your stylesheet

<style>
.site-nav {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; padding: 14px 24px; background: #111;
}
.site-nav .sn-logo { color: #fff; font-weight: 800; font-size: 1.15rem; text-decoration: none; }
.site-nav .sn-links { list-style: none; display: flex; gap: 24px; margin: 0; padding: 0; }
.site-nav .sn-links a { color: #cbd5e1; text-decoration: none; font-size: .95rem; }
.site-nav .sn-links a:hover { color: #fff; }
.site-nav .sn-toggle { display: none; font-size: 1.5rem; line-height: 1; background: none; border: none; color: #fff; cursor: pointer; }

@media (max-width: 640px) {
  .site-nav .sn-toggle { display: inline-flex; }
  .site-nav .sn-links { display: none; flex-direction: column; width: 100%; gap: 4px; padding-top: 12px; }
  .site-nav .sn-links.open { display: flex; }
}
</style>

3. JavaScript — paste before </body>

<script>
  const navToggle = document.querySelector('.site-nav .sn-toggle');
  const navLinks  = document.querySelector('.site-nav .sn-links');
  navToggle.addEventListener('click', () => {
    const open = navLinks.classList.toggle('open');
    navToggle.setAttribute('aria-expanded', open);
    navToggle.setAttribute('aria-label', open ? 'Close menu' : 'Open menu');
  });
</script>
Full Page

The whole thing as one file

Everything above — a responsive navbar, breadcrumbs, a pill sub-nav, page content, and a back-to-top button — combined into one complete HTML file. Save it as index.html, open it in a browser, and it just works — no libraries, no build step. Here's the live result, then the full code.

Live preview

Complete HTML — copy this whole file

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My Site</title>
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; color: #1f2433; background: #f8fafc; }

    /* ===== Responsive top navbar ===== */
    .site-nav {
      display: flex; align-items: center; justify-content: space-between;
      flex-wrap: wrap; padding: 14px 24px; background: #111;
      position: sticky; top: 0; z-index: 100;   /* stays pinned while scrolling */
    }
    .site-nav .sn-logo { color: #fff; font-weight: 800; font-size: 1.15rem; text-decoration: none; }
    .site-nav .sn-links { list-style: none; display: flex; gap: 24px; }
    .site-nav .sn-links a { color: #cbd5e1; text-decoration: none; font-size: .95rem; }
    .site-nav .sn-links a:hover { color: #fff; }
    .site-nav .sn-toggle { display: none; font-size: 1.5rem; line-height: 1; background: none; border: none; color: #fff; cursor: pointer; }

    /* ===== Breadcrumbs ===== */
    .bc { display: flex; align-items: center; gap: 8px; list-style: none; font-size: 14px; color: #666; padding: 16px 24px; flex-wrap: wrap; }
    .bc a { color: #666; text-decoration: none; }
    .bc a:hover { color: #111; }
    .bc li { display: flex; align-items: center; gap: 8px; }
    .bc li + li::before { content: "/"; color: #ccc; }
    .bc .current { color: #111; font-weight: 600; }

    /* ===== Pill sub-nav ===== */
    .pill-nav { display: inline-flex; padding: 6px; gap: 4px; background: #fff; border: 1px solid #eee; border-radius: 999px; margin: 0 24px; }
    .pill-nav a { padding: 8px 18px; border-radius: 999px; text-decoration: none; color: #555; font-size: 14px; font-weight: 600; }
    .pill-nav a:hover { color: #111; }
    .pill-nav a.active { background: #111; color: #fff; }

    /* ===== Page content ===== */
    main { max-width: 760px; margin: 0 auto; padding: 24px; }
    main h1 { font-size: 2rem; margin-bottom: 12px; }
    main p { color: #4b5563; margin-bottom: 14px; }

    /* ===== Back-to-top button ===== */
    .to-top {
      position: fixed; bottom: 22px; right: 22px;
      width: 46px; height: 46px; border-radius: 999px;
      background: #111; color: #fff; border: none; cursor: pointer;
      font-size: 1.3rem; line-height: 1; display: none;
      box-shadow: 0 10px 30px rgba(0,0,0,.2);
    }
    .to-top.show { display: block; }

    /* ===== Mobile: collapse links into the menu button ===== */
    @media (max-width: 640px) {
      .site-nav .sn-toggle { display: inline-flex; }
      .site-nav .sn-links { display: none; flex-direction: column; width: 100%; gap: 4px; padding-top: 12px; }
      .site-nav .sn-links.open { display: flex; }   /* JS toggles .open */
    }
  </style>
</head>
<body>

  <nav class="site-nav" aria-label="Main">
    <a class="sn-logo" href="index.html">Brandr</a>
    <button class="sn-toggle" aria-label="Open menu" aria-expanded="false">&#9776;</button>
    <ul class="sn-links">
      <li><a href="#">Home</a></li>
      <li><a href="#">Features</a></li>
      <li><a href="#">Pricing</a></li>
      <li><a href="#">About</a></li>
    </ul>
  </nav>

  <ul class="bc">
    <li><a href="#">Home</a></li>
    <li><a href="#">Docs</a></li>
    <li class="current">Navigation</li>
  </ul>

  <nav class="pill-nav" aria-label="Sections">
    <a href="#" class="active">Overview</a>
    <a href="#">Guides</a>
    <a href="#">API</a>
  </nav>

  <main>
    <h1>Welcome to my site</h1>
    <p>This page combines the navigation patterns from the lab: a sticky responsive navbar, a breadcrumb trail, a pill sub-nav, and a back-to-top button.</p>
    <p>Make the window narrow and the navbar links collapse into the &#9776; menu button. Scroll down and a round button appears in the corner to jump back to the top.</p>
    <p style="height: 800px;">Plenty of room to scroll…</p>
    <p>You made it to the bottom — tap the button to fly back up.</p>
  </main>

  <button class="to-top" aria-label="Back to top">&#8593;</button>

  <script>
    // Mobile menu toggle
    const navToggle = document.querySelector('.site-nav .sn-toggle');
    const navLinks = document.querySelector('.site-nav .sn-links');
    navToggle.addEventListener('click', () => {
      const open = navLinks.classList.toggle('open');
      navToggle.setAttribute('aria-expanded', open);
      navToggle.setAttribute('aria-label', open ? 'Close menu' : 'Open menu');
    });

    // Back-to-top button
    const toTop = document.querySelector('.to-top');
    window.addEventListener('scroll', () => {
      toTop.classList.toggle('show', window.scrollY > 200);
    });
    toTop.addEventListener('click', () => {
      window.scrollTo({ top: 0, behavior: 'smooth' });
    });
  </script>
</body>
</html>