跪拜 Guibai
← All articles
Frontend · JavaScript · Programmer

Six CSS Features That Replace Whole JavaScript Libraries in 2026

By ErpanOmer ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Every line of JavaScript replaced by a CSS feature removes a main-thread bottleneck. Scroll-driven animations alone eliminate the highest-frequency event handler in most web apps, while anchor positioning lets teams drop an entire dependency tree for tooltip logic.

Summary

A set of six CSS capabilities — :has(), @container, scroll-driven animations, @starting-style, field-sizing: content, and CSS Anchor Positioning — now handle interaction patterns that previously required JavaScript libraries or fragile event-listener hacks. Each replaces a specific pain point: parent-to-child state awareness, component-level responsive layouts, scroll-bound progress bars and parallax, entry animations on display:none elements, auto-resizing textareas, and tooltip positioning with overflow flipping.

The performance story is the sharper argument. Scroll-driven animations run on the compositor thread, bypassing main-thread congestion entirely. Anchor positioning computes layout at the engine level, avoiding getBoundingClientRect calls and reflow-triggered recalculations. The shift isn't cosmetic — it moves interaction logic from JavaScript's single-threaded runtime into the browser's native rendering pipeline.

Browser support for all six features is now universal across Chrome, Firefox, Safari, and Edge, making them safe for production use without polyfills. The practical upshot is smaller bundles, fewer dependencies, and a rendering path that doesn't stall on user input.

Takeaways
:has() lets a parent style itself based on a child's state — form:has(:invalid) disables submit buttons without a single event listener.
@container queries switch a component's layout when its own container resizes, not when the viewport changes, removing the need for ResizeObserver.
Scroll-driven animations bind keyframes to scroll progress via animation-timeline: scroll() and execute on the compositor thread, not the main thread.
@starting-style defines the initial state for a discrete property transition, making display:none-to-block fade-ins possible in pure CSS.
field-sizing: content on a textarea auto-expands height as the user types, replacing the classic scrollHeight recalculation hack.
CSS Anchor Positioning pins a tooltip to a named anchor element and handles boundary overflow with position-try-fallbacks, making Popper.js unnecessary.
Conclusions

The compositor-thread execution of scroll-driven animations isn't a minor optimization — it's an architectural shift that moves animation scheduling out of JavaScript's single-threaded event loop entirely.

CSS Anchor Positioning's position-try-fallbacks property bakes in the overflow-flipping logic that made Floating UI a non-trivial library, suggesting browser vendors are deliberately absorbing utility-library territory.

The allow-discrete keyword in transition declarations signals a broader trend: CSS is gaining first-class support for animating properties that were previously considered un-animatable, which could shrink the footprint of animation libraries like Framer Motion for common UI patterns.

Concepts & terms
animation-timeline: scroll()
A CSS property that links an animation's progress to the scroll position of an element, rather than to a time duration. The browser's compositor thread drives the animation, so it never blocks the main JavaScript thread.
@starting-style
A CSS at-rule that defines the initial property values for an element's first frame when it transitions from a non-rendered state (like display:none). It solves the long-standing problem of animating elements that are being inserted into the DOM.
allow-discrete
A keyword added to the transition-property value that enables CSS transitions on discrete properties — properties like display and visibility that have no intermediate computed values. Without it, browsers skip the transition entirely.
position-try-fallbacks
A CSS property for anchor-positioned elements that specifies a list of alternative positions the browser should try if the element overflows its containing block. It provides native tooltip-flipping behavior without JavaScript.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗