How to Make a Navigation Bar in HTML & CSS (Responsive)

Quick answer

<nav class="navbar"> <ul> <li><a href="/">Home</a></li> <li><a href="/about/">About</a></li> <li><a href="/contact/">Contact</a></li> </ul> </nav> <style> .navbar ul { display: flex; gap: 24px; list-style: none; margin: 0; padding: 0; } </style>

Step 1: Write the HTML for the menu

A navigation bar is a list of links, so that’s how to mark it up:

  1. 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.
  2. 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”).
  3. 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.

index.html
Preview

Step 2: Turn it into a horizontal bar with flexbox

  1. Remove the bullets and the list’s default spacing: list-style: none; margin: 0; padding: 0; on the ul.
  2. Line the items up in a row: display: flex on the ul, with gap for the space between them.
  3. Style the links: remove the underline, set a color, and add padding so each link is a comfortable click target.
  4. Add a :hover style, 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.

index.html
Preview

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.

index.html
Preview

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.

index.html
Preview

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:

  1. Add a <button> with aria-expanded="false" and aria-controls pointing at the list’s id.
  2. 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 an open class.
  3. With a few lines of JavaScript, toggle the open class when the button is clicked, and update aria-expanded so 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.

index.html
Preview

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: relative and the nested list position: absolute; top: 100%;, hidden by default and shown when the parent has an open class.

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

FeatureHowWhy
Semantic markup<nav> + <ul> of linksScreen readers and search engines recognise the menu
Horizontal layoutdisplay: flex on the listSimple, wraps neatly, easy spacing with gap
Big click targetsPadding on the links (display: block)Easier to tap, especially on phones
Current pagearia-current="page"Visitors know where they are
Keyboard focusKeep or restyle :focus-visibleKeyboard users can see which link is selected
Mobile menuToggle button + media queryLinks 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> with display: 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.

Frequently asked questions

How do I make a navigation bar in HTML?
Put an unordered list of links inside a <nav> element, then use CSS to remove the bullets (list-style: none) and place the links in a row with display: flex on the list.
How do I make a horizontal navigation bar?
Give the <ul> inside your <nav> display: flex, list-style: none, margin: 0 and padding: 0. The list items then sit side by side, and gap controls the space between them.
How do I make the navigation bar stay at the top when scrolling?
Add position: sticky and top: 0 to the navigation bar, plus a background color and a z-index so the page content scrolls underneath it.
How do I make a responsive navigation bar?
Use a media query to hide the links on small screens and show a menu button instead. A few lines of JavaScript toggle a class that shows the links when the button is clicked, and update aria-expanded.
Should a navigation bar use a list?
For most menus, yes. A list tells screen reader users how many links there are and is easy to style. Very short menus with two or three links can use plain links inside <nav>.
How do I show which page is active in the menu?
Add aria-current="page" to the link for the current page and style it with the CSS selector a[aria-current="page"], for example with a different color or an underline.