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:
- Dropdown menus: Use
:hoveron a parent<li>to reveal a submenu - Sticky navbar: Add
position: sticky; top: 0; z-index: 100;to the nav - Scroll effect: Use a small JavaScript snippet to add a shadow class after the user scrolls down
- Smooth transitions: Animate the mobile menu opening with
max-heighttransitions
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.