---
title: "A sticky navbar that morphs when it sticks, no JS"
description: "scroll-state container queries let the browser tell you when a sticky element is stuck, so you can restyle it on scroll with pure CSS. No scroll listeners, no animation library. Chromium-only for now."
date: "2026-04-09"
tags: ["css", "container-queries", "scroll", "frontend"]
---

You know the move: a full-width navbar that, once you scroll past it, shrinks
into a floating pill. Until recently that meant a scroll listener, an
`IntersectionObserver`, or a sprinkle of JS toggling a class. Not anymore.
[Manu Arora](https://x.com/mannupaaji/status/2060025609867387239) showed it off
with pure CSS, and the key is a feature I'd missed: scroll-state container
queries.

Scroll the box above (in a Chromium browser). The bar starts edge-to-edge, then
the instant it sticks, it pulls in and rounds off into a pill.

## The whole thing

```css
header {
  container-type: scroll-state;
  position: sticky;
  top: 0;
}

@container scroll-state(stuck: top) {
  .nav-bar {
    max-width: 56rem;
    border-radius: 0.75rem;
    background: rgb(255 255 255 / 0.92);
  }
}
```

Two parts. `container-type: scroll-state` turns the sticky `header` into a
container the browser tracks scroll state for. Then `@container
scroll-state(stuck: top)` matches whenever that container is currently stuck to
the top, and you restyle anything inside it. The browser does the detecting; you
just write the stuck-state styles. Add a `transition` on the inner element and
the morph animates for free.

  src="/videos/scroll-state-navbar.mp4"
  className="my-6 w-full rounded-xl border border-[hsl(var(--border))]"
  autoPlay
  muted
  loop
  playsInline
/>

## The catch

It's Chromium-only right now. No Firefox, no Safari, which is a shame for
something this clean. But it degrades nicely: where `scroll-state` isn't
supported, the query just never matches and your navbar stays in its default
state. So treat the morph as an enhancement, make sure the un-morphed bar is
perfectly usable on its own, and you can ship it today without breaking anyone.

Via [@mannupaaji](https://x.com/mannupaaji/status/2060025609867387239).
