The menu (navigation) lined up at the top of a page is an important part that’s both the face of a site and its signpost. This article collects 9 ready-to-use navigation menus, each with a live demo. From the basic horizontal layout to a hamburger menu, just copy and swap the color and link destinations.
HTMLBuild the framework of a pageFor the meaning of the “nav” tag used for navigation, head to this lesson in the HTML course.First, the shared groundwork
Since a menu is really “a list of links,” the HTML is basically a <ul> and <a> placed inside a <nav>. Lists come with bullets and spacing by default, so resetting them first with this .nav lets any design sit cleanly on top.
<nav>
<ul class="nav">
<li><a href="#">Home</a></li>
<li><a href="#">About Me</a></li>
<li><a href="#">Works</a></li>
</ul>
</nav>.nav {
display: flex;
gap: 4px;
margin: 0;
padding: 0;
list-style: none;
}
.nav a {
display: block;
padding: 8px 16px;
color: #333;
font-weight: bold;
text-decoration: none;
}From here on, the designs are used by adding classes on top of this groundwork.
The basic horizontal layout
A basic horizontal nav
Start here. Site name on the left, menu on the right—the classic arrangement used on sites all over the world. justify-content: space-between means “distribute to both ends.”
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 20px;
background: #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}A faint box-shadow plays the role of the boundary that says “the header ends here.”
A pill-hover nav
A nav where only the item you hover gets a capsule-shaped background that fades in softly. It clearly conveys where you can press.
.pill {
border-radius: 999px;
transition: background 0.2s, color 0.2s;
}
.pill:hover {
background: #ff8a3d;
color: #fff;
}A nav where an underline slides out
On hover, a line slides out from the center under the item. It’s a refined, classic motion that fits sites of any design.
.underline {
position: relative;
}
.underline::after {
content: "";
position: absolute;
left: 16px;
right: 16px;
bottom: 4px;
height: 3px;
border-radius: 3px;
background: #ff8a3d;
transform: scaleX(0);
transition: transform 0.25s;
}
.underline:hover::after {
transform: scaleX(1);
}The mechanism is “place the line in advance, and normally squash it to zero width (scaleX(0)).” Restoring it to its original width on hover makes it look like it stretches from the center.
A nav that shows the current page
Showing “which page am I on right now” is also an important job of a nav. Add the current class to the item for the page you’re on, and change its color.
.nav a.current {
background: #ff8a3d;
color: #fff;
}Just move current to the item for each page. It makes visitors less likely to get lost.
There’s a reason the selector is written as .nav a.current and not just .current. Since the text color is already set with .nav a, with just .current, .nav a wins regardless of the order you write them in, so the text won’t turn white. When you’re targeting the same a, make this selector more specific than .nav a too so it wins out.
It follows even when you scroll
A fixed header (sticky)
Even when you scroll down the page, only the header sticks to the top of the screen. All you need are the two lines position: sticky and top: 0.
.sticky {
position: sticky;
top: 0;
}sticky behaves like this: it sits normally most of the time, and sticks once it reaches the edge of the screen. Even on a long page, the menu is always within reach.
The mobile staple: the hamburger menu
On a narrow phone screen, the classic is to tuck the menu into a three-line button (a hamburger button) and open it on press.
A hamburger menu made with CSS only
A method that uses a checkbox’s on/off as the open/close switch without JavaScript. The checkbox itself is hidden, and only the label (the three lines) is shown.
.menu-check {
position: absolute;
opacity: 0;
width: 0;
height: 0; /* hidden visually, but keyboard focus stays */
}
.drawer {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s;
}
.menu-check:checked ~ .drawer {
max-height: 200px; /* open when checked */
}The heart of it is the last block. Combining :checked (while it’s checked) and ~ (a following element within the same parent), it says “when checked, release the height of the menu.”
A hamburger menu made with JavaScript (turns into an ×)
A more full-featured form where pressing the button transforms the three lines into an ×. The open/close toggle can be written in a few lines of JavaScript.
const btn = document.getElementById("btn");
btn.addEventListener("click", function () {
document.querySelector(".header").classList.toggle("open");
});JavaScript’s only job is “add or remove the open class when pressed.” Both the transformation into an × and the opening and closing of the menu are written on the CSS side as the look for when open is added.
Switching by screen width
On real sites, the classic is to switch “horizontal on desktop, hamburger on mobile.” The switch is done with a media query (branching by screen width), swapping the show/hide of the horizontal nav and the hamburger button.
/* Normally (desktop): hide the button, show the horizontal nav */
.menu-btn {
display: none;
}
/* Swap on screens 600px and narrower (mobile) */
@media (max-width: 600px) {
.menu-btn {
display: flex;
}
.pc-nav {
display: none;
}
}Just give the horizontal nav a name like class="pc-nav". With this framework alone, you can combine any horizontal nav and hamburger menu in this article. Adjust the switching boundary (600px) to the width where your own menu starts to feel cramped.
When there are many items
A dropdown menu
Hover over an item and a submenu opens below it. It suits organizing sites that have grown in page count.
.has-child {
position: relative;
}
.child {
position: absolute;
top: 100%;
left: 0;
opacity: 0;
visibility: hidden;
transition:
opacity 0.2s,
visibility 0.2s;
}
.has-child:hover .child {
opacity: 1;
visibility: visible;
}The submenu is “hidden right below the parent (top: 100%) and shown on the parent’s hover.” Using opacity and visibility instead of display: none gives a soft show/hide transition.
A checklist for when the menu goes wrong
- The bullets or left spacing won’t go away → Did you add
list-style: noneandpadding: 0to the<ul>? - The link’s clickable area is narrow → Give the
<a>display: blockandpadding. It prevents the state where only the text part is clickable. - sticky isn’t working → It won’t work if a parent element has
overflow: hidden. Check the header’s parent. - The dropdown’s submenu is out of place → Did you forget to add
position: relativeto the parent<li>?
Summary
- A menu is really a list of links—reset the
<nav>+<ul>, and line them up horizontally withdisplay: flexfor the basic form. - Hover motion (a pill background, a stretching underline) and showing the current page make it more helpful as a signpost.
- For mobile, use a hamburger menu—a checkbox for CSS only, or a few lines of JavaScript when you want to fine-tune the effect.
Just pick one form you like and swap the color, and the entrance to your site becomes much more polished.