CSS Tutorial
CSS Navigation Bars
A navigation bar is just a list of links styled to look like a menu. In this tutorial you will turn a plain unordered list into polished horizontal and vertical navigation bars using CSS, complete with hover states, an active link, and a sticky bar that stays at the top of the page.
The Building Block: A List of Links
Semantically, a navbar is an unordered list (ul) of links (a) inside a nav element. Screen readers and search engines understand this structure, and CSS turns it into a menu. The three core steps are: remove the default list bullets and spacing, lay the items out, then style the links.
ul {
list-style-type: none;
margin: 0;
padding: 0;
}Vertical Navigation Bar
For a vertical menu, keep the list items stacked (their default) and make each link a block so the entire row is clickable, not just the text.
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: system-ui, sans-serif; }
ul.side { list-style: none; margin: 0; padding: 0; width: 180px; background: #f1f5f9; }
ul.side li a { display: block; color: #0f172a; padding: 12px 16px; text-decoration: none; border-left: 4px solid transparent; }
ul.side li a:hover { background: #0f766e; color: #fff; }
ul.side li a.active { border-left-color: #0f766e; font-weight: bold; }
</style>
</head>
<body>
<ul class="side">
<li><a class="active" href="#home">Home</a></li>
<li><a href="#news">News</a></li>
<li><a href="#jobs">Jobs</a></li>
<li><a href="#about">About</a></li>
</ul>
</body>
</html>Horizontal Navigation Bar
The modern way to build a horizontal navbar is to make the list a flex container. Every list item then sits in a row automatically, and you gain easy control over spacing and alignment.
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: system-ui, sans-serif; margin: 0; }
ul.topnav { list-style: none; margin: 0; padding: 0; display: flex; background: #1e293b; }
ul.topnav li a { display: block; color: #cbd5e1; padding: 14px 20px; text-decoration: none; }
ul.topnav li a:hover { background: #334155; color: #fff; }
ul.topnav li a.active { background: #0f766e; color: #fff; }
ul.topnav li.right { margin-left: auto; }
</style>
</head>
<body>
<ul class="topnav">
<li><a class="active" href="#home">Home</a></li>
<li><a href="#news">News</a></li>
<li><a href="#jobs">Jobs</a></li>
<li class="right"><a href="#login">Login</a></li>
</ul>
</body>
</html>margin-left: auto on one list item pushes it and everything after it to the far right of a flex navbar - perfect for a Login or Sign up button.
Common Navbar Styles
| Property | Purpose |
|---|---|
| list-style-type: none | Removes the bullet points |
| display: flex | Lays items out in a horizontal row |
| display: block (on links) | Makes the whole item area clickable |
| text-decoration: none | Removes the default underline on links |
| :hover | Highlights a link as the mouse passes over it |
| position: sticky / fixed | Keeps the bar visible while scrolling |
Sticky Navigation Bar
position: sticky keeps the navbar pinned to the top of the viewport once you scroll past it, while still flowing normally before that. Scroll the example to see it stay in place.
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: system-ui, sans-serif; margin: 0; }
.topnav { position: sticky; top: 0; display: flex; background: #0f766e; }
.topnav a { color: #fff; padding: 14px 20px; text-decoration: none; }
.topnav a:hover { background: #0d5f59; }
.content { padding: 20px; height: 900px; background: linear-gradient(#ecfeff, #cffafe); }
</style>
</head>
<body>
<div class="topnav">
<a href="#home">Home</a>
<a href="#news">News</a>
<a href="#jobs">Jobs</a>
</div>
<div class="content">
<h2>Scroll down</h2>
<p>The teal navigation bar stays pinned to the top of the frame.</p>
</div>
</body>
</html>position: sticky needs a top (or bottom) value to know where to stick, and it will not work if a parent element has overflow: hidden or overflow: auto set.
Key points
- A navbar is a ul of links inside a nav element - start by removing list bullets and default padding.
- Use display: flex on the list for a horizontal bar; keep items stacked for a vertical one.
- Make links display: block so the entire menu cell is clickable.
- Add a .active class to highlight the current page.
- position: sticky with top: 0 pins the bar while the user scrolls.
