Advertisement

Smart CSS Anchored Selection Pills

| by Vladimir | 3 min read | code by Jhey
A11y Ready Advanced

Tech & Dependencies

HTML CSS Babel
GSAP Tweakpane

Features

  • Anchor Positioning
  • Mask Composition
  • Tweakpane Config
  • Progressive Enhancement

Browser Support

Chrome 125+ Edge 125+ Safari 26+ Firefox 147+

Core

This Smart CSS Anchored Selection Pills component demonstrates the bleeding edge of CSS layout capabilities. It uses the new CSS Anchor Positioning API to tether a visual “pill” indicator to the currently selected radio button without JavaScript calculations for position. The demo includes a robust fallback system that calculates positions via ResizeObserver for browsers that don’t yet support anchors, ensuring a consistent experience across the board. It also features advanced masking techniques (SVG and CSS Filters) to create “knockout” text effects where the selected text changes color inversely to the pill background.

Core Technique

The implementation showcases two distinct strategies for positioning the selection indicator:

  1. Native CSS Anchors: When supported, the .pill element is positioned relative to the focused/checked label using position-anchor: --active. The CSS top, left, width, and height properties use anchor() functions (e.g., top: anchor(top)). This delegates all layout logic to the browser’s layout engine, resulting in zero-latency updates during resizing or reflows.

  2. JavaScript Fallback (Polyfill-like behavior): For browsers without anchor support, a ResizeObserver monitors the container. When the layout changes or an input is clicked, JavaScript calculates the getBoundingClientRect of the selected label relative to the container and updates CSS custom properties (--top, --left, --width, --height) on the parent. The .pill then uses these variables for positioning.

Additionally, a creative “Knockout” Effect is achieved using either mask-image with a dynamically generated SVG (updated via JS on resize) or CSS filter: url(#knockout-black) with feColorMatrix to invert colors based on the background luminance.

Customization

The component is highly configurable via the Tweakpane control panel in the demo, but in code, you can adjust the transition physics and styles in the CSS layers.

@layer anchor {
  @supports (anchor-name: --active) {
    .pill {
      /* Link pill dimensions to the anchor */
      top: anchor(top);
      left: anchor(left);
      width: anchor-size(width);
      height: anchor-size(height);
      position-anchor: --active;
      
      /* Smooth transition for movement */
      transition-property: left, top, width;
      transition-duration: calc(var(--duration, 0.2) * 1s);
      transition-timing-function: ease-out;
    }
    
    /* Define the anchor on the label preceding the checked input */
    label:has(+ :checked) {
      anchor-name: --active;
    }
  }
}

To modify the “knockout” text color logic, check the SVG filter definitions in the HTML. The matrix values determine how colors are shifted.

Tips

1. Progressive Enhancement First: This snippet is a perfect example of progressive enhancement. It checks CSS.supports('anchor-name: --active') before executing heavy JavaScript layout logic. This means users on modern browsers get a lighter, performant experience, while others still get full functionality.

2. Handling Dynamic Content: If your labels change size (e.g., loading different text or fonts), the ResizeObserver is crucial even with Anchor Positioning for edge cases where layout shifts might desynchronize complex masks. The demo handles this by observing the entire container.

Advertisement