State, Logic, and Native Power: CSS Wrapped 2025

How CSS evolved into a powerful system for handling state, logic, and complex interactions without JavaScript

The CSS Revolution Has Arrived

CSS in 2025 has fundamentally transformed from a styling language into a powerful system for handling state, logic, and complex interactions--capabilities that previously required JavaScript. The browser platform now provides native tools that enable developers to build responsive, stateful, and interactive interfaces using pure CSS, reducing bundle sizes and improving performance.

This evolution represents a paradigm shift: CSS can now respond to container dimensions, scroll states, element relationships, and user interactions without custom JavaScript. By leveraging these native capabilities, development teams can create faster, more accessible, and more maintainable interfaces that scale across projects.

For organizations investing in professional web development services, understanding these capabilities provides a competitive advantage in building modern digital experiences.

Modern CSS Capabilities

Key features that define CSS development in 2025

Container Queries

Component-level responsiveness based on container dimensions, not viewport

Scroll-State Queries

Style elements based on scroll position, sticky state, and snap points

Style Queries

Respond to computed styles on parent containers conditionally

Customizable Select

Full styling control over native select elements with CSS

CSS Carousel Primitives

Native scroll-marker and scroll-button for carousel navigation

Anchor Positioning

Declarative positioning relative to anchor elements with fallback detection

Container Queries: The Foundation of Component-Based Design

Container queries enable you to apply styles to an element based on certain attributes of its container: the container's size, styles applied to the container, and the container's scroll-state. This represents a fundamental shift from media queries, which apply styles based on viewport size, to container queries that respond to the actual space available to a component.

For teams practicing modern web development with component-based architectures, container queries enable truly reusable components that adapt to their context rather than relying on viewport assumptions. This approach aligns with component-driven development patterns where each component manages its own responsive behavior.

Container Types

The container-type property establishes different types of containment contexts:

TypeDescription
sizeQuery based on inline and block dimensions with full layout containment
inline-sizeQuery based on inline dimension only, lighter containment
normalNot a query container for size queries, but supports style queries

Container Query Length Units

Container query length units specify a length relative to the dimensions of a query container, making components flexible across different containers:

UnitDescription
cqw1% of a query container's width
cqh1% of a query container's height
cqi1% of a query container's inline size
cqb1% of a query container's block size
cqminThe smaller value of either cqi or cqb
cqmaxThe larger value of either cqi or cqb

Learn more about container queries from MDN's comprehensive guide

Container Query Example
1/* Create a containment context */2.card-container {3 container-type: inline-size;4 container-name: card;5}6 7/* Apply styles based on container size */8@container card (width > 700px) {9 .card {10 display: grid;11 grid-template-columns: 2fr 1fr;12 }13 14 .card-title {15 font-size: clamp(1.25rem, 3cqi, 2rem);16 }17}18 19/* Fallback for containers narrower than 700px */20@container card (width <= 700px) {21 .card {22 display: flex;23 flex-direction: column;24 }25}

The :has() Selector: CSS Can Now Think in State

The :has() pseudo-class represents a transformative leap in CSS capabilities, enabling parent selection and sibling selection with state awareness. Previously impossible in CSS, :has() allows you to style elements based on the presence or state of their children or subsequent siblings.

This capability opens entirely new patterns for responsive and conditional styling, reducing the need for JavaScript-based class manipulation. When combined with modern CSS techniques, developers can create sophisticated interactive patterns that would previously require substantial client-side logic.

Practical Applications

  • Style a parent card differently when it contains a featured image
  • Create responsive layouts that adapt based on which child elements are present
  • Build form validation feedback that responds to input states
  • Create conditional layouts based on content structure

These patterns integrate seamlessly with component libraries and align with best practices for building maintainable front-end architectures.

CSS :has() Selector Examples
1/* Style cards based on their contents */2.card:has(.featured-image) {3 grid-template-columns: 1fr 2fr;4}5 6/* Add badges to cards that contain promo content */7.card:has(.promo-tag) {8 position: relative;9}10 11.card:has(.promo-tag)::before {12 content: 'PROMO';13 position: absolute;14 top: -10px;15 right: -10px;16 background: #e63946;17 color: white;18 padding: 0.25rem 0.5rem;19 border-radius: 4px;20 font-size: 0.75rem;21 font-weight: bold;22}23 24/* Form validation feedback */25.form-group:has(input:invalid:not(:placeholder-shown)) {26 --error-color: #dc2626;27}28 29.form-group:has(input:focus) label {30 color: #0066cc;31}

Scroll-State Queries: Responding to Scroll Behavior

Chrome 133 introduced scroll-state container queries, enabling CSS to detect and respond to scroll-related states. This revolutionary feature allows styling elements based on whether they're stuck, snapped, or overflowing--without JavaScript IntersectionObserver implementations.

For performance-critical applications, eliminating JavaScript scroll detection can significantly improve Time to Interactive metrics. The browser handles scroll-state detection on the compositor thread, avoiding main-thread blocking that can cause janky scroll behavior and impact Core Web Vitals scores.

Available States

  • stuck: top/bottom/left/right - Detects sticky positioning state and edge
  • snapped: self/none - Detects if element is snapped in a scroll container
  • overflowing - Detects if content overflows the container

Use Cases

  • Sticky headers with dynamic shadows that appear when stuck
  • Active navigation highlighting as users scroll through sections
  • Carousel indicators that show which slide is currently in view
  • Scroll-spy table of contents with active section highlighting

Explore the official Chrome documentation on scroll-state queries

Scroll-State Query Examples
1/* Sticky header with dynamic shadow */2.header-container {3 container-type: scroll-state;4 position: sticky;5 top: 0;6 z-index: 100;7}8 9header {10 transition: box-shadow 0.3s ease, background 0.3s ease;11 background: white;12}13 14/* Only show shadow when header is actually stuck */15@container scroll-state(stuck: top) {16 header {17 box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);18 }19}20 21/* Carousel active state */22.carousel-item {23 scroll-snap-align: center;24 flex: 0 0 80%;25 transition: transform 0.3s ease, opacity 0.3s ease;26}27 28@container scroll-state(snapped: self) {29 .carousel-item {30 transform: scale(1.1);31 opacity: 1;32 z-index: 10;33 }34}

Customizable Select: The End of JavaScript Dropdowns

One of the most requested features in CSS history has arrived: the ability to fully customize native <select> elements. Using appearance: base-select, developers can now style every part of a select element, including the button, dropdown list, and individual options.

This advancement eliminates the need for custom dropdown libraries that add substantial JavaScript payload. Teams can now build accessible, performant select components using pure CSS while maintaining semantic HTML structure.

Key Features

  • Full CSS control over the button, dropdown list, and options
  • Top-layer rendering ensures dropdowns appear above all content
  • Automatic positioning that flips based on available viewport space
  • HTML content support in options including images and icons
  • Progressive enhancement with graceful fallback

Check the Chrome Dev documentation for the latest customizable select API details

Customizable Select Styling
1/* Enable customizable select styling */2select,3select::picker(select) {4 appearance: base-select;5}6 7/* Style the select button */8select {9 background: linear-gradient(to bottom, #fff, #f8f9fa);10 border: 2px solid #dee2e6;11 border-radius: 12px;12 padding: 0.875rem 3rem 0.875rem 1.25rem;13 font-size: 1rem;14 min-width: 200px;15 cursor: pointer;16 transition: all 0.2s ease;17}18 19select:hover {20 border-color: #0066cc;21}22 23select:focus {24 outline: none;25 border-color: #0066cc;26 box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.2);27}28 29/* Style the dropdown list */30select::picker(select) {31 background: white;32 border-radius: 12px;33 box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15);34 padding: 0.5rem;35 margin-top: 0.5rem;36}37 38/* Style individual options */39select::picker(select) option {40 padding: 0.75rem 1rem;41 border-radius: 8px;42 cursor: pointer;43}44 45select::picker(select) option:hover {46 background: #f0f7ff;47}

CSS Carousel Primitives: Scroll-Marker and Scroll-Button

The CSS Carousel API introduces native pseudo-elements for creating accessible, performant carousels without JavaScript libraries. The browser handles marker grouping, state management, and button behavior automatically.

New Pseudo-Elements

  • ::scroll-marker - Navigation dots or markers for carousel items
  • ::scroll-button - Scroll buttons (previous/next arrows)
  • ::scroll-marker-group - Container for grouping markers
  • :target-current - Pseudo-class for the currently active marker

By leveraging these native primitives, developers can create carousel components that are significantly smaller in bundle size and benefit from browser-level performance optimizations. This approach reduces the maintenance burden of keeping third-party carousel libraries updated.

See Smashing Magazine's comprehensive coverage for detailed carousel code examples and demos

CSS Carousel Primitives Example
1/* Basic carousel structure */2.carousel {3 overflow-x: auto;4 scroll-snap-type: x mandatory;5 scroll-marker-group: after;6 display: flex;7 gap: 1rem;8 padding: 1rem;9}10 11.carousel-item {12 scroll-snap-align: center;13 flex: 0 0 80%;14 height: 300px;15 border-radius: 12px;16 background: linear-gradient(135deg, #667eea, #764ba2);17}18 19/* Style scroll markers */20.carousel::scroll-marker {21 width: 12px;22 height: 12px;23 border-radius: 50%;24 background: #dee2e6;25 cursor: pointer;26 transition: all 0.2s ease;27}28 29.carousel::scroll-marker:target-current {30 background: #0066cc;31 transform: scale(1.25);32}33 34/* Style scroll buttons */35.carousel::scroll-button(inline-start),36.carousel::scroll-button(inline-end) {37 content: '';38 width: 40px;39 height: 40px;40 border-radius: 50%;41 background: white;42 box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);43 cursor: pointer;44 align-self: center;45}46 47.carousel::scroll-button(inline-start)::before {48 content: '◀';49 display: flex;50 align-items: center;51 justify-content: center;52 height: 100%;53}54 55.carousel::scroll-button(inline-end)::before {56 content: '▶';57 display: flex;58 align-items: center;59 justify-content: center;60 height: 100%;61}

Anchor Positioning and Anchored Container Queries

CSS anchor positioning enables declarative positioning of elements relative to anchor elements, with automatic fallback handling. Combined with anchored container queries, you can detect which fallback position was used and adapt styles accordingly.

Key Concepts

  • anchor-name - Defines an anchor reference on an element
  • position-anchor - Links a positioned element to an anchor
  • position-area - Specifies the anchor area for positioning
  • position-try-fallbacks - Automatic repositioning when space is limited
  • Anchored queries - Style based on which fallback was used

These capabilities simplify the implementation of tooltips, popovers, and dropdown menus while ensuring consistent behavior across viewport sizes.

Anchor Positioning with Fallback Detection
1/* Define anchor element */2.trigger-button {3 anchor-name: --tooltip-trigger;4}5 6/* Position tooltip relative to anchor */7.tooltip {8 position-anchor: --tooltip-trigger;9 position-area: top;10 position-try-fallbacks: flip-block, flip-inline, closest-side;11 container-type: anchored;12}13 14/* Default arrow pointing down */15.tooltip::before {16 content: '';17 position: absolute;18 bottom: -8px;19 left: 50%;20 transform: translateX(-50%);21 border-left: 8px solid transparent;22 border-right: 8px solid transparent;23 border-top: 8px solid #333;24}25 26/* Flip arrow when using flip-block fallback */27@container anchored(fallback: flip-block) {28 .tooltip::before {29 content: '';30 bottom: auto;31 top: -8px;32 border-top: none;33 border-bottom: 8px solid #333;34 }35}36 37/* Different positioning for inline flip */38@container anchored(fallback: flip-inline) {39 .tooltip::before {40 left: auto;41 right: -8px;42 top: 50%;43 transform: translateY(-50%);44 border: none;45 border-left: 8px solid #333;46 }47}

Invoker Commands: Declarative Interactions

The Invoker Commands API enables buttons to perform actions on other elements without JavaScript event handlers. Using commandfor and command attributes, developers can create interactive UI patterns purely in HTML.

For teams building interactive web applications, invoker commands reduce the amount of glue code needed to connect buttons to their target elements. This declarative approach improves code organization and reduces potential sources of bugs.

Built-in Commands

  • show-popover / hide-popover / toggle-popover - Popover API control
  • show-modal - Open dialogs modally
  • close - Close dialogs
  • Custom commands with -- prefix (handled via command event)
Invoker Commands HTML Examples
1<!-- Open a dialog without JavaScript -->2<button commandfor="settings-dialog" command="show-modal">3 Open Settings4</button>5 6<!-- Toggle a popover -->7<button commandfor="menu-popover" command="toggle-popover">8 Menu9</button>10 11<!-- Close a dialog -->12<dialog id="settings-dialog">13 <h2>Settings</h2>14 <p>Configure your preferences here.</p>15 16 <!-- Custom command handler via JavaScript -->17 <button commandfor="settings-dialog" command="--save-settings">18 Save19 </button>20 21 <button commandfor="settings-dialog" command="close">22 Close23 </button>24</dialog>25 26<!-- Popover example -->27<div id="menu-popover" popover>28 <nav>29 <a href="/">Home</a>30 <a href="/about">About</a>31 <a href="/contact">Contact</a>32 </nav>33</div>

Performance Benefits of Native CSS

Using native CSS features instead of JavaScript solutions provides significant performance advantages:

Zero JavaScript Bundle Impact

Native CSS features add no JavaScript to your bundle, reducing download size, parse time, and execution time. Every kilobyte of JavaScript eliminated improves Time to Interactive (TTI) and Core Web Vitals scores.

Browser-Optimized Rendering

Browser rendering engines are highly optimized for CSS. Native features leverage the same code paths used for browser UI, benefiting from ongoing performance improvements across all browsers.

Main Thread Offloading

CSS-based interactions run on the browser's compositor thread, separate from the main JavaScript thread. This prevents interaction blocking during heavy JavaScript operations and provides smoother 60fps animations.

Automatic Accessibility

Native CSS features include proper ARIA attribute management, keyboard navigation, and focus handling. Building with platform features ensures accessible interactions without custom implementation.

Progressive Enhancement

CSS gracefully degrades when features aren't supported. Users with modern browsers get enhanced experiences, while users with older browsers receive functional baselines without broken functionality.

These performance characteristics make modern CSS an essential consideration for SEO-focused web development, where page speed directly impacts search rankings and user experience.

Progressive Enhancement Strategy

Implementing modern CSS while supporting older browsers requires thoughtful progressive enhancement:

Feature Detection

Use @supports to detect browser capabilities and provide appropriate fallbacks:

/* Base styles for all browsers */
.card { ... }

/* Enhanced styles for supporting browsers */
@supports (container-type: inline-size) {
 .card {
 /* Container query-based responsive behavior */
 }
}

/* Legacy fallback */
@supports not (container-type: inline-size) {
 @media (min-width: 700px) {
 .card {
 /* Media query-based responsive behavior */
 }
 }
}

Testing Matrix

Test across multiple browser versions:

  • Chrome 100+ (full feature support)
  • Firefox 110+ (container queries, scroll-state in progress)
  • Safari 16+ (container queries, :has())
  • Edge 100+ (equivalent to Chrome)

This testing approach ensures your implementations work reliably across the browser landscape while taking advantage of newer features where supported.

Conclusion

CSS in 2025 represents a fundamental transformation in frontend development. The language now supports state management, conditional logic, and complex interactions natively, enabling developers to build faster, more accessible, and more maintainable interfaces.

Key Takeaways

  1. Container queries enable truly component-based responsive design
  2. Scroll-state queries replace complex JavaScript scroll detection
  3. The :has() selector enables parent and sibling selection
  4. Customizable select eliminates JavaScript dropdown libraries
  5. CSS carousel primitives provide native carousel functionality
  6. Anchor positioning simplifies tooltip and popover implementations
  7. Invoker commands enable declarative interactions without JavaScript

By embracing these features while maintaining progressive enhancement strategies, development teams can deliver excellent experiences to modern browser users while ensuring broad compatibility. The investment in learning and implementing modern CSS pays dividends in reduced bundle sizes, improved performance, and more maintainable codebases.


Sources:

Frequently Asked Questions

Ready to Build Modern Web Applications?

Our team specializes in leveraging the latest web technologies to build fast, accessible, and maintainable digital experiences.