Utilities✨ Premium

Adaptive Navigation

One navigation, three shapes depending on its container's width: a menu button that opens the list, inline links from 320 px, a sidebar from 480 px.

CSS@containerNavigation

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Utilities has 43 effects, including 3 free. Explore the category →

3 usage examples

Ferrovane — the same navigation in the header and as a docs sidebar — Adaptive Navigation example 1

① Ferrovane — the same navigation in the header and as a docs sidebar

WhenA tool's documentation site: at the top, a 400 px navigation (Product, Pricing, Docs, Blog) shows inline next to “Sign in”; below, the same navigation, placed in the page's 520 px area, becomes the docs sidebar (Get started, Guides, API, Changelog) with the article on the right.
WhyOne navigation component for the whole site; each spot gives it its shape, no variant to write.
SettingsTwo roots: header (width: 400px, transparent background and shell, content hidden) and page (height: 100%, #10151c background, block content with title, text and code). Red accent on the active link set by the scene.
Maquelis — bakery template in a mock-up tool — Adaptive Navigation example 2

② Maquelis — bakery template in a mock-up tool

WhenA mock-up tool: a frame with a handle holds the site template of a bakery, Pétrinelle. Dragging the handle moves the navigation from the menu button (210 px) to inline links and then to the sidebar beyond 480 px; the width shows at the top.
WhyThe client sees the three shapes of their menu in seconds, with the real component, before signing off the mock-up.
SettingsRoot from 210 to 516 px, light colours set by the scene (shell #fffaf3, nav #f3e9da, links #5b4330); the content is a welcome banner. Handle and counter belong to the scene; for the capture the frame narrows and widens on its own in 1.4 s.
Brévaunes cottage — menu of a booking widget that is too narrow — Adaptive Navigation example 3

③ Brévaunes cottage — menu of a booking widget that is too narrow

WhenA holiday cottage page: on the right, a 250 px booking widget. Its menu (The cottage, Rates, Getting here, Contact) fits in a button; a click opens the list above the calendar, a second click closes it.
WhyIn a narrow spot the links stay reachable instead of disappearing; the calendar keeps its full width.
Settings250 px root, white background, nav #f4f8f3, button lines #2f4f2f, active link #15803d. For the capture, the widget's real button is clicked every 0.7 s; the capture mouse's clicks outside the menu also close it.

How it works

The .fx-0757-root element is the queried container (container: anv-nav / inline-size). It holds .anv-shell, with the <nav class="anv-nav"> (the .anv-logo brand, the .anv-burger button and a single <ul class="anv-links"> list) followed by the .anv-content area, where your page content goes. The links exist only once in the HTML: only their layout changes.

Below 320 px, the bar shows the brand and a three-line button; the list is hidden. The button adds the is-open class to the nav and sets aria-expanded to true: the list opens as a column under the bar and pushes the content down, the lines turn into a cross. Escape closes it (and returns focus to the button if it was inside the menu), as do a click outside, a click on a link or tabbing out of the menu.

From 320 px, @container anv-nav (min-width: 320px) hides the button and lines the links up to the right of the brand. From 480 px, the shell becomes a 160px 1fr grid: the nav turns into a vertical sidebar (brand on top, links stacked) and the content is centred to its right. The script attaches once per root, with no id; the clicked link gets aria-current="page".

Accessibility

  • Real menu button: a <button type="button"> named “Menu”, with aria-expanded; the list follows the button in reading order, so Tab goes straight to the first link once the menu is open.
  • Keyboard closing: Escape closes the menu and puts focus back on the button; tabbing past the last link closes it too, without trapping focus.
  • Real links: <a href> in a <ul> inside a <nav aria-label>; the active link carries aria-current="page". In Safari, Tab only stops on links with Option+Tab or the macOS keyboard setting.
  • Visible focus: 2 px #a78bfa outline on the brand, the button and the links. Button target: 32 × 32 px.
  • Reduced motion: the menu always opens without animation; under prefers-reduced-motion: reduce, the links' hover fade is removed too.

Browser compatibility

Container queries (Chrome 105, Firefox 110, Safari 16), Element.closest(), :focus-visible (Safari 15.4). Measured in Chromium 151, Firefox 153 and WebKit 26.5 with two copies on one page: button shown up to 319 px, inline links from 321 to 479 px, sidebar from 481 px; at 280 px, the 2nd copy's button opens only the 2nd (4 links visible and clickable) on click, tap and Enter; Escape, outside click and focus leaving close it; 0 errors.

Chrome 105+✓ Full (measured)
Firefox 110+✓ Full (measured)
Safari 16+✓ Full (measured in WebKit)
Edge 105+✓ Full
Mobile iOS 16+✓ Full
Android Chrome 105+✓ Full

Without container queries, the nav keeps its narrow shape (button + collapsible list) at every width, still usable. Without JavaScript, the button opens nothing below 320 px: keep the script, or repeat the links in the footer.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0757-root">
  <div class="anv-shell">
    <nav class="anv-nav" aria-label="…">
      <div class="anv-head">
        <a class="anv-logo" href="#">…</a>
        <button type="button" class="anv-burger" aria-expanded="false" aria-label="Menu">…</button>
      </div>
      <ul class="anv-links">
        <li><a href="#…" aria-current="page">…</a></li>
        <li><a href="#…">…</a></li>
      </ul>
    </nav>
    <div class="anv-content">…</div>
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Breakpoints (CSS — @container anv-nav (min-width: 320px) and (min-width: 480px)) 320 px inline links, 480 px sidebar Fit them to your labels' length: with six links, raise the first one towards 420 px.
Sidebar width (CSS — grid-template-columns: 160px 1fr) 160 px Widen it for long labels.
Links (HTML — .anv-links) Home, About, Blog, Contact One <li><a> per link; aria-current="page" on the current page.
Brand (HTML — .anv-logo) “Brand” text, colour #986ef7 Replace it with your name or a logo <img alt>.
Content (HTML — .anv-content) “Page content area” Put your page in it; in sidebar mode it is centred: switch it to display: block for running text.
Colours (CSS) Shell rgba(255,255,255,.05), links rgba(255,255,255,.7), active link #c4b5fd On a light background, also change the button lines (.anv-burger span).

FAQ

No: it opens in the flow, under the bar, and pushes the content down. Nothing can be clipped by an overflow: hidden parent. For an overlay menu, set .anv-links to position: absolute in your CSS.
Beyond 320 px the button disappears and the links show inline, whether the menu was open or not; there is nothing to close.
It depends on the root's width. If the nav sits in a 400 px header it stays inline; give it the page's full width (480 px or more) to get the sidebar.