SolutionsCase StudiesAI ToolsResourcesAboutContact
Get Your Free AI Automation Audit Book a Free 30-Minute Strategy Call
Playground~/frontend Open editor

~/css/responsive-navbars

7 CSS Responsive Navbars

3 Pure CSS4 with JSPublished 2026-10-05Free · no sign-up

Seven ways a navbar can adapt to small screens: a hamburger toggle, a priority plus bar that moves overflow links into a More menu, a scrolling row of links, a full-screen overlay, a logo above wrapping links, a menu built on details with no script and a slide-in drawer.

01. Hamburger Toggle Below 480px

ResponsiveHamburger

Links sit in a row on wide containers and collapse behind a Menu button on narrow ones, opening as a vertical list below the bar. The breakpoint is a container query, so the navbar responds to the space it is given, not the window.

View code
<div class="rn1"><nav aria-label="Main"><a class="logo" href="#home">Kite</a><button aria-expanded="false" aria-controls="rn1l" class="mb"><span aria-hidden="true">☰</span> Menu</button><ul id="rn1l"><li><a href="#product">Product</a></li><li><a href="#pricing">Pricing</a></li><li><a href="#docs">Docs</a></li><li><a href="#login">Log in</a></li></ul></nav></div>
.rn1 { width: 600px; max-width: 100%; container-type: inline-size; font: 600 14px Inter, system-ui, sans-serif; }
.rn1 nav { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 18px; padding: 12px 16px; border: 1px solid #e4e7ec; border-radius: 12px; background: #fff; }
.rn1 .logo { margin-right: auto; color: #101828; font-weight: 900; font-size: 18px; text-decoration: none; }
.rn1 ul { display: flex; gap: 18px; margin: 0; padding: 0; list-style: none; }
.rn1 ul a { color: #344054; text-decoration: none; }
.rn1 .mb { display: none; padding: 7px 12px; border: 1px solid #d0d5dd; border-radius: 8px; background: #fff; font: inherit; cursor: pointer; }
.rn1 a:focus-visible, .rn1 button:focus-visible { outline: 3px solid #84adff; outline-offset: 2px; border-radius: 6px; }
@container (max-width: 479px) {
  .rn1 .mb { display: block; }
  .rn1 ul { display: none; flex-basis: 100%; flex-direction: column; gap: 0; }
  .rn1 ul.open { display: flex; } .rn1 ul a { display: block; padding: 10px 0; border-top: 1px solid #f2f4f7; }
}
var b = document.querySelector('.rn1 .mb'), l = document.getElementById('rn1l');
b.onclick = function () { var o = l.classList.toggle('open'); b.setAttribute('aria-expanded', o); };

02. Priority Plus: Overflow into More

ResponsivePriority plus

Links that fit stay visible and the rest move into a More menu, so the most important links never disappear behind a hamburger. A ResizeObserver measures the bar and moves list items between the two lists in source order.

View code
<div class="rn2"><nav aria-label="Sections"><ul class="vis"><li><a href="#news">News</a></li><li><a href="#sport">Sport</a></li><li><a href="#culture">Culture</a></li><li><a href="#science">Science</a></li><li><a href="#travel">Travel</a></li><li><a href="#food">Food</a></li></ul><div class="more" hidden><button aria-expanded="false" aria-controls="rn2m">More</button><ul id="rn2m" hidden></ul></div></nav></div>
.rn2 { width: 560px; max-width: 100%; resize: horizontal; overflow: hidden; min-width: 180px; padding-bottom: 120px; font: 600 14px Inter, system-ui, sans-serif; }
.rn2 nav { position: relative; display: flex; align-items: center; padding: 8px 10px; border-radius: 12px; background: #151b2e; }
.rn2 ul { margin: 0; padding: 0; list-style: none; }
.rn2 .vis { display: flex; flex: 1; min-width: 0; gap: 4px; overflow: hidden; }
.rn2 a { display: block; padding: 7px 10px; border-radius: 8px; color: #cbd5e1; text-decoration: none; white-space: nowrap; } .rn2 a:hover { background: #1e2640; color: #fff; }
.rn2 .more { position: relative; }
.rn2 button { padding: 7px 10px; border: 0; border-radius: 8px; background: #263048; color: #fff; font: inherit; cursor: pointer; }
.rn2 #rn2m { position: absolute; right: 0; top: calc(100% + 6px); min-width: 140px; padding: 6px; border-radius: 10px; background: #1e2640; }
.rn2 :focus-visible { outline: 2px solid #93c5fd; outline-offset: 1px; }
var nav = document.querySelector('.rn2 nav'), vis = nav.querySelector('.vis'), more = nav.querySelector('.more'), mb = more.querySelector('button'), list = document.getElementById('rn2m');
function fit() {
  while (list.firstElementChild) vis.appendChild(list.firstElementChild);
  more.hidden = true;
  if (vis.scrollWidth <= vis.clientWidth) return;
  more.hidden = false;
  while (vis.scrollWidth > vis.clientWidth && vis.lastElementChild) list.insertBefore(vis.lastElementChild, list.firstChild);
}
mb.onclick = function () { var o = mb.getAttribute('aria-expanded') !== 'true'; mb.setAttribute('aria-expanded', o); list.hidden = !o; };
new ResizeObserver(fit).observe(nav);

03. Scrollable Link Row with Fades

ResponsiveScroll

On narrow screens the links stay in one row that scrolls sideways, with faded edges hinting that there is more, the pattern news and shop sites use for categories. The fade is a mask on the list, and the row is a labelled navigation landmark.

View code
<nav class="rn3" aria-label="Categories"><ul><li><a href="#all" aria-current="page">All</a></li><li><a href="#dresses">Dresses</a></li><li><a href="#knitwear">Knitwear</a></li><li><a href="#trousers">Trousers</a></li><li><a href="#shoes">Shoes</a></li><li><a href="#bags">Bags</a></li><li><a href="#jewellery">Jewellery</a></li></ul></nav>
.rn3 { width: 320px; max-width: 100%; font: 600 14px Inter, system-ui, sans-serif; }
.rn3 ul { display: flex; gap: 6px; margin: 0; padding: 4px 16px; list-style: none; overflow-x: auto; scrollbar-width: none; -webkit-mask: linear-gradient(90deg, transparent, #000 16px, #000 calc(100% - 24px), transparent); mask: linear-gradient(90deg, transparent, #000 16px, #000 calc(100% - 24px), transparent); }
.rn3 ul::-webkit-scrollbar { display: none; }
.rn3 a { display: block; padding: 8px 14px; border: 1px solid #d0d5dd; border-radius: 999px; color: #344054; text-decoration: none; white-space: nowrap; }
.rn3 a[aria-current] { background: #101828; border-color: #101828; color: #fff; }
.rn3 a:focus-visible { outline: 3px solid #84adff; outline-offset: 1px; }

04. Full-Screen Overlay Menu

ResponsiveOverlay

The menu button opens a full-screen overlay with large links, built on a modal dialog so focus is trapped inside it, the page behind is inert and Escape closes it. The overlay fades in with @starting-style.

View code
<div class="rn4"><header><a class="logo" href="#home">Field</a><button class="open" aria-haspopup="dialog">Menu</button></header><dialog aria-label="Menu"><button class="close" aria-label="Close menu">&times;</button><nav aria-label="Main"><a href="#work">Work</a><a href="#studio">Studio</a><a href="#journal">Journal</a><a href="#contact">Contact</a></nav></dialog></div>
.rn4 { width: 400px; max-width: 100%; font-family: Inter, system-ui, sans-serif; }
.rn4 header { display: flex; justify-content: space-between; align-items: center; padding: 12px 14px; border-radius: 12px; background: #151b2e; }
.rn4 .logo { color: #fff; font-weight: 900; font-size: 18px; text-decoration: none; }
.rn4 .open { padding: 7px 12px; border: 1px solid #3a4670; border-radius: 8px; background: transparent; color: #fff; font: 600 13px Inter, system-ui, sans-serif; cursor: pointer; }
.rn4 dialog { width: 100%; max-width: 100%; height: 100%; max-height: 100%; margin: 0; padding: 24px; box-sizing: border-box; border: 0; background: #0b1020; color: #fff; opacity: 0; transition: opacity .25s, overlay .25s allow-discrete, display .25s allow-discrete; }
.rn4 dialog[open] { opacity: 1; } @starting-style { .rn4 dialog[open] { opacity: 0; } }
.rn4 .close { float: right; width: 44px; height: 44px; border: 0; border-radius: 50%; background: #1e293b; color: #fff; font-size: 24px; cursor: pointer; }
.rn4 dialog nav { display: grid; gap: 6px; margin-top: 60px; }
.rn4 dialog nav a { color: #f8fafc; font-size: 34px; font-weight: 800; text-decoration: none; } .rn4 dialog nav a:hover { color: #fbbf24; }
.rn4 :focus-visible { outline: 2px solid #fbbf24; outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .rn4 dialog { transition: none; } }
var d = document.querySelector('.rn4 dialog');
document.querySelector('.rn4 .open').onclick = function () { d.showModal(); };
d.querySelector('.close').onclick = function () { d.close(); };
d.querySelectorAll('nav a').forEach(function (a) { a.onclick = function () { d.close(); }; });

05. Logo Above Links on Mobile

ResponsiveCentred

Some sites have few enough links that no hamburger is needed: on narrow containers the logo sits centred above a wrapping row of links, on wide ones it moves to the left. Every link stays visible at every size, which is the most usable option of all.

View code
<div class="rn5"><nav aria-label="Main"><a class="logo" href="#home">Olive &amp; Oak</a><ul><li><a href="#menu">Menu</a></li><li><a href="#book">Book</a></li><li><a href="#visit">Visit</a></li></ul></nav></div>
.rn5 { width: 560px; max-width: 100%; container-type: inline-size; font: 600 14px Inter, system-ui, sans-serif; }
.rn5 nav { display: grid; justify-items: center; gap: 8px; padding: 14px; border-bottom: 2px solid #1c1917; background: #fafaf9; }
.rn5 .logo { color: #1c1917; font: italic 700 22px Georgia, serif; text-decoration: none; }
.rn5 ul { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 18px; margin: 0; padding: 0; list-style: none; }
.rn5 ul a { color: #44403c; text-decoration: none; } .rn5 ul a:hover { color: #1c1917; text-decoration: underline; }
.rn5 a:focus-visible { outline: 2px solid #1c1917; outline-offset: 3px; }
@container (min-width: 440px) { .rn5 nav { display: flex; justify-content: space-between; align-items: center; } }

06. No-JavaScript Menu with details

ResponsiveNo JS

A collapsible menu that needs no script at all: the menu is a details element whose summary is the Menu button, and on wide containers a container query hides the summary and shows the links as a row. It works even before JavaScript loads.

View code
<div class="rn6"><nav aria-label="Main"><a class="logo" href="#home">Atlas</a><details><summary>Menu</summary><ul><li><a href="#maps">Maps</a></li><li><a href="#guides">Guides</a></li><li><a href="#about">About</a></li></ul></details></nav></div>
.rn6 { width: 560px; max-width: 100%; container-type: inline-size; font: 600 14px Inter, system-ui, sans-serif; }
.rn6 nav { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 8px; padding: 12px 14px; border-radius: 12px; background: #151b2e; }
.rn6 .logo { color: #fff; font-weight: 900; font-size: 18px; text-decoration: none; }
.rn6 summary { padding: 6px 12px; border: 1px solid #3a4670; border-radius: 8px; color: #fff; cursor: pointer; list-style: none; }
.rn6 summary::-webkit-details-marker { display: none; }
.rn6 ul { margin: 8px 0 0; padding: 0; list-style: none; } .rn6 ul a { display: block; padding: 8px 0; color: #cbd5e1; text-decoration: none; }
.rn6 :focus-visible { outline: 2px solid #93c5fd; outline-offset: 2px; border-radius: 6px; }
@container (min-width: 420px) {
  .rn6 nav { align-items: center; }
  .rn6 details summary { display: none; }
  .rn6 details::details-content { content-visibility: visible; display: contents; }
  .rn6 ul { display: flex; gap: 18px; margin: 0; }
}

07. Side Drawer Navigation

ResponsiveDrawer

The menu slides in from the left as a modal drawer over a dimmed page. The native dialog element handles focus trapping and Escape, the slide is a transform transition with @starting-style, and clicking the dimmed backdrop closes it.

View code
<div class="rn7"><button class="open"><span aria-hidden="true">☰</span> Menu</button><dialog aria-label="Menu"><nav aria-label="Main"><a href="#home" aria-current="page">Home</a><a href="#shop">Shop</a><a href="#orders">Orders</a><a href="#help">Help</a></nav><button class="close">Close</button></dialog></div>
.rn7 { font: 600 14px Inter, system-ui, sans-serif; }
.rn7 .open { padding: 9px 14px; border: 1px solid #d0d5dd; border-radius: 8px; background: #fff; font: inherit; cursor: pointer; }
.rn7 dialog { position: fixed; inset: 0 auto 0 0; width: min(240px, 80vw); height: 100%; max-height: none; margin: 0; padding: 20px; box-sizing: border-box; border: 0; background: #fff; transform: translateX(-100%); transition: transform .3s cubic-bezier(.2,.8,.2,1), overlay .3s allow-discrete, display .3s allow-discrete; }
.rn7 dialog[open] { transform: none; } @starting-style { .rn7 dialog[open] { transform: translateX(-100%); } }
.rn7 dialog::backdrop { background: rgba(16,24,40,.45); }
.rn7 nav { display: grid; gap: 4px; margin-bottom: 16px; }
.rn7 nav a { padding: 10px; border-radius: 8px; color: #344054; text-decoration: none; } .rn7 nav a[aria-current] { background: #f2f4f7; color: #101828; }
.rn7 .close { padding: 8px 12px; border: 1px solid #d0d5dd; border-radius: 8px; background: #fff; font: inherit; cursor: pointer; }
.rn7 :focus-visible { outline: 3px solid #84adff; outline-offset: 1px; }
@media (prefers-reduced-motion: reduce) { .rn7 dialog { transition: none; } }
var d = document.querySelector('.rn7 dialog');
document.querySelector('.rn7 .open').onclick = function () { d.showModal(); };
d.querySelector('.close').onclick = function () { d.close(); };
d.addEventListener('click', function (e) { if (e.target === d) d.close(); });

About these CSS Responsive Navbars

Hide as little as possible

If the links fit, show them. A centred logo above a wrapping row, or a scrolling row with faded edges, keeps navigation visible; priority plus hides only what does not fit.

Menus are buttons

A menu toggle is a real <button> with aria-expanded and aria-controls, and a visible word such as Menu next to any icon helps people recognise it.

Overlays and drawers are dialogs

Full-screen menus and drawers cover the page, so build them on <dialog> with showModal(): focus is trapped, the page behind is inert and Escape closes them.

Respond to the container

A navbar inside a narrow layout region should collapse even on a wide screen. Container queries let the same component collapse wherever it is placed.

Frequently asked questions

Is the hamburger icon understood?

Mostly, but adding the word Menu beside it measurably helps.

Does the details menu work without JavaScript?

Yes. It opens and closes with no script at all.

How does priority plus decide what to hide?

It measures the bar and moves the last links into the More menu until the rest fit.