Detecting the exact moment a `position: sticky` header "sticks" to the top — to add a shadow, say — has always needed JS, since CSS had no way to know whether it was currently stuck. The usual approach was an IntersectionObserver watching a sentinel element.
`@container scroll-state(stuck: top)` asks that question directly, in container-query syntax. Give the parent `container-type: scroll-state` and children can restyle based on stuck/snapped/scrollable state inside a scroll container. Where scroll-driven animation handles continuous scroll progress, this handles discrete state changes caused by scrolling — the two complement each other.
Check caniuse/MDN baseline for support. Without it, an IntersectionObserver watching a sentinel element and toggling a class remains the standard fallback.
When to use
Adding a shadow when a sticky header sticks, or enabling a button based on scroll-snap state.