How to Make a Navigation Bar in HTML & CSS
To make a navigation bar, put a list of links inside a <nav> element: <nav><ul><li><a href="/">Home</a></li></ul></nav>. Then use CSS to remove the bullets and line the links up in a row with display: flex. A few more lines add hover effects, an active page and a mobile menu.
Last updated: October 4, 2026
Quick answer
Step 1: Write the HTML for the menu
A navigation bar is a list of links, so that’s how to mark it up:
- Wrap the menu in a
<nav>element. It tells browsers, search engines and screen readers “this is the site’s main navigation”, and screen reader users can jump straight to it. - Inside it, use an unordered list
<ul>with one<li>per menu item. Screen readers then announce how many links there are (“list, 4 items”). - Put an
<a href>link inside each list item.
Without CSS, this shows up as a plain bulleted list, which is exactly what it is. The styling comes next.
Step 2: Turn it into a horizontal bar with flexbox
- Remove the bullets and the list’s default spacing:
list-style: none; margin: 0; padding: 0;on theul. - Line the items up in a row:
display: flexon theul, withgapfor the space between them. - Style the links: remove the underline, set a color, and add padding so each link is a comfortable click target.
- Add a
:hoverstyle, so people can see what they’re pointing at.
The example also adds a logo on the left. Putting justify-content: space-between on the bar pushes the logo and the menu to opposite ends, and flex-wrap: wrap lets the links drop onto a second line instead of running off the edge when space is tight. In the full editor’s Desktop view they sit in one row.
Step 3: Highlight the current page
Visitors should be able to see which page they’re on. Mark the current page’s link with aria-current="page": screen readers announce it as “current page”, and you can style it in CSS with the attribute selector a[aria-current="page"]. This is better than a plain class="active", because it helps everyone, not just sighted visitors.
On a site built from separate HTML files, put aria-current="page" on a different link in each file. Website builders and frameworks usually add it for you.
Step 4: Keep the navigation bar at the top (sticky)
To keep the menu visible while people scroll, add two lines to the bar: position: sticky; top: 0;. It scrolls normally until it reaches the top of the window, then stays there. Add a z-index so page content slides under it, and give it a background color so text doesn’t show through.
position: fixed also pins a bar to the top, but it takes the bar out of the page flow, so the content underneath needs extra top padding. sticky avoids that.
A short menu with three or four links doesn’t strictly need a list; the example above uses plain links inside <nav>. Both are valid. The list version is the common choice for longer menus.
Step 5: Add a mobile menu (hamburger button)
On a phone there’s rarely room for a row of links. The usual solution is a menu button (often a ☰ “hamburger” icon) that shows and hides the links:
- Add a
<button>witharia-expanded="false"andaria-controlspointing at the list’sid. - In CSS, hide the button on wide screens. On narrow screens (a media query such as
max-width: 600px), show the button and hide the list unless the nav has anopenclass. - With a few lines of JavaScript, toggle the
openclass when the button is clicked, and updatearia-expandedso screen readers know whether the menu is open.
This preview is narrower than 600 pixels, so the menu button is showing: click it. Open the example in the full editor and choose Desktop to see the links in a row instead.
Adding a dropdown menu
For a section with several pages, such as “Services”, you can nest a second list inside a menu item and show it as a dropdown. Keep two things in mind:
- Use a button to open it, not only hover. Hover doesn’t exist on touch screens, and keyboard users need a way in. A
<button aria-expanded="false">next to the link, toggled with JavaScript like the mobile menu above, works for everyone. - Position it under its parent. Give the parent
<li>position: relativeand the nested listposition: absolute; top: 100%;, hidden by default and shown when the parent has anopenclass.
If you only have a handful of pages, skip dropdowns entirely: a flat menu is faster to use and easier to build.
Navigation bar checklist
| Feature | How | Why |
|---|---|---|
| Semantic markup | <nav> + <ul> of links | Screen readers and search engines recognise the menu |
| Horizontal layout | display: flex on the list | Simple, wraps neatly, easy spacing with gap |
| Big click targets | Padding on the links (display: block) | Easier to tap, especially on phones |
| Current page | aria-current="page" | Visitors know where they are |
| Keyboard focus | Keep or restyle :focus-visible | Keyboard users can see which link is selected |
| Mobile menu | Toggle button + media query | Links fit on small screens |
Common mistakes when making a navbar
- Using
<div>s instead of<nav>and a list. It looks the same but hides the menu’s purpose from assistive technology. - Making menu items buttons or clickable divs. Navigation goes to pages, so use real
<a href>links. - Padding on the
<li>instead of the link. Only the text is clickable then. Put the padding on the<a>withdisplay: block. - A mobile menu that only works on hover. Touch screens have no hover. Use a button that toggles on click.
- Forgetting
aria-expanded. Screen reader users can’t tell whether the menu is open. - Too many links. Five to seven top-level items is a good limit; group the rest into dropdowns or the footer.