Utilities✨ Premium

Responsive Nav

Tab bar that shows icons only in a narrow column and adds its labels once its container reaches 280 px — no media query.

CSS@containerNav

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

Crestoval — the same bar on a phone and a tablet — Responsive Nav example 1

① Crestoval — the same bar on a phone and a tablet

WhenLanding page of a hiking app: two mock-ups side by side, a 156 px phone and a 324 px tablet, each with its trail list and the same Trails / Explore / Profile bar at the bottom. Nothing moves: each bar reads the width of its own screen.
WhyOne component for every screen size in the app: users see the words when there is room, and the team does not build two bars.
SettingsRoot in a screen-footer block (128 px in the phone, 288 px in the tablet); root background transparent, bar background rgba(217,249,157,.06). Labels and links replaced in the HTML.
Corvessane — footer of a note-taking window being widened — Responsive Nav example 2

② Corvessane — footer of a note-taking window being widened

WhenDesktop window of a notes app: a note being written and, at the bottom, the Notes / Search / Account bar. Dragging the window corner makes the labels appear as soon as the bar reaches 280 px, and vanish when it is narrowed again.
WhyIn a resizable app the bar keeps the same height: it gains words instead of wrapping or overflowing.
SettingsRoot in the window footer, transparent background. The corner handle belongs to the scene: drag it with the mouse or the arrow keys; for the capture the window widens on its own between 236 and 492 px.
Talmirenc — bar of a floating podcast player that shrinks — Responsive Nav example 3

③ Talmirenc — bar of a floating podcast player that shrinks

WhenA podcast show's site: a floating player at the bottom right shows the current episode and an Episodes / Search / Account bar. The “Shrink” button narrows the player from 316 to 190 px: the bar keeps only its icons without being touched.
WhyA component placed inside an element that changes size follows on its own; no class to toggle on the bar itself.
SettingsRoot inside the player (296 px then 170 px), transparent background, bar padding: 6px 8px. The “Shrink” button is the scene's; for the capture it is replayed every 1.3 s.

How it works

The .fx-0746-root element is the queried container itself (container: ctb-nav / inline-size). It holds a <nav class="ctb-bar"> with one .ctb-item link per tab: a decorative SVG icon and a <span class="ctb-label">. What decides the layout is the width of the spot where you place the bar, not the screen width: the same bar can show its labels in the page and stay icon-only in a side column.

Below 280 px the labels are hidden from sight with the visually-hidden technique (1 px box, clip-path: inset(50%)): they stay in the page and name the links. The @container ctb-nav (min-width: 280px) rule puts them back next to the icon. Tabs stay centred, 6 px apart, on a rgba(255,255,255,.04) background with 14 px corners.

The active tab is the one carrying aria-current="page": violet rgba(139,92,246,.2) background, #8b5cf6 icon, #a78bfa label. The small script attaches to each root (once, even if pasted twice) and moves that attribute to the clicked link; on a multi-page site, simply set aria-current on the server.

Accessibility

  • Real links: each tab is an <a href>, reached with Tab and followed with Enter, by finger or mouse. In Safari, Tab only stops on links with Option+Tab or the macOS “Use Tab to select” setting.
  • Name kept in icon mode: the label is hidden from sight, not removed: a screen reader says “Search, link” even at 160 px wide. Icons carry aria-hidden="true".
  • Current tab announced: aria-current="page" is read out (“current page”). Visually, the active tab stands out through a violet background and text colour: if you want a cue that does not rely on colour, add an underline or a bar under .ctb-item[aria-current="page"].
  • Visible focus: 2 px #a78bfa outline offset by 2 px on :focus-visible.
  • Reduced motion: under prefers-reduced-motion: reduce, the 0.3 s background and colour fades are removed; labels have always appeared instantly.

Browser compatibility

Container queries (container-type, @container: Chrome 105, Firefox 110, Safari 16) and :focus-visible (Safari 15.4). Measured in Chromium 151, Firefox 153 and WebKit 26.5 with two copies on one page: labels hidden up to 279 px, shown from 281 px, still on one line at 800 px; click, tap and Enter move the active tab of the touched copy only; 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 (older browser), the bar stays icon-only at every width; labels are still read by screen readers and the links work. Without JavaScript, only the active tab moving on click is lost.

The code

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

index.html — structure
<div class="fx-0746-root">
  <nav class="ctb-bar" aria-label="…">
    <a class="ctb-item" href="#…" aria-current="page">
      <svg aria-hidden="true">…</svg>
      <span class="ctb-label">…</span>
    </a>
    <a class="ctb-item" href="#…">…</a>
  </nav>
</div>

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

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Breakpoint (CSS — @container ctb-nav (min-width: 280px)) 280 px Change the value to show labels earlier or later; it applies to the root's width.
Tabs (HTML — .ctb-item) 3 links: Home, Search, Profile Add or remove links; with more tabs, raise the breakpoint so every label fits on one line.
Active tab (HTML — aria-current="page") The first link Put the attribute on the current page's link; the script moves it on click in a single-page app.
Accent colour (CSS — .ctb-item[aria-current="page"]) Background rgba(139,92,246,.2), icon #8b5cf6, text #a78bfa Replace these three values for the active tab, and rgba(139,92,246,.15) for hover.
Background (CSS — .fx-0746-root and .ctb-bar) #0a0a0f with 16 px corners, bar rgba(255,255,255,.04) Set the root to background: transparent so it takes your footer's colour.
Icons (HTML — 24 × 24 stroke <svg>) House, magnifier, person; 1.5 stroke Paste your own stroke icons (fill: none): their colour follows the tab state.

FAQ

The bar looks at its root's width, not the window's. If the root sits in a 240 px column it stays icon-only even on a big screen: widen the column or lower the 280 px breakpoint.
Yes. The text is hidden from sight but stays in the page: it names the links for screen readers and voice control (“click Search”).
Only if your tabs don't change page (single-page app, tabs of a panel). On a regular site each page sets aria-current="page" on its own link and the script can go: the width adaptation is pure CSS.