The History of CSS Container Queries
For over a decade, web developers requested a way to style elements based on the size of their containing element rather than the viewport. The idea was simple: a card component should be able to reflow its layout when the card's container is narrow, regardless of how wide the browser window is.
The difficulty was the "layout infinite loop" problem. If a query changes an element's size, and that size change triggers another query, the browser could loop forever. Solving this required the concept of containment — a way to declare that an element's size is determined entirely by its content or its parent, not by its children.
After years of specification work and polyfills from the community, native CSS container queries shipped in all major browsers in 2023. The syntax was elegant: @container (min-width: 400px) could be written almost like a media query.
From Size to State
Size container queries were just the beginning. The CSS Working Group quickly moved on to style container queries — the ability to query the computed value of CSS custom properties on an ancestor element. This unlocked data-driven theming without JavaScript.
But developers wanted more. Sticky elements had always been a pain point: you could make a header stick to the top, but detecting when it was stuck required a JavaScript IntersectionObserver — an ugly workaround that felt wrong for a purely presentational concern.
Scroll state container queries, shipping in Chrome 149, solve this natively. Three new scroll conditions let CSS respond directly to the browser's own scroll state tracking: stuck, snapped, and scrollable. No JavaScript. No observers. No layout thrash.
Three Conditions, Infinite Possibilities
The stuck condition matches sticky elements that are currently pinned against their specified offset edge. stuck: top fires when a position: sticky; top: 0 header is pinned. stuck: bottom fires when a footer with position: sticky; bottom: 0 is stuck to the bottom of the viewport — as is the bar below this article.
The snapped condition exposes the scroll snap state. Carousels can now style their active slide in pure CSS. Vertical story readers can highlight the focused card. No more index-tracking in JavaScript.
The scrollable condition tells you whether a scroll container still has overflow in a given direction. Fade overlays and scroll arrows can be shown or hidden declaratively. The chevron buttons in a sidebar disappear when you've scrolled to the end.