---
title: "Modern CSS & HTML Cheat Sheet: 115 Features, Support & What to Try Next"
description: "A scannable checklist of modern CSS and HTML features—grouped by layout, selectors, color, typography, animation and more, plus declarative HTML additions like `<geolocation>`, `focusgroup` and Invoker Commands—each with its purpose, an example, and browser support."
canonical_url: "https://neillin.com/en/blog/css-techniques-checklist/"
last_updated: "2026-10-13"
---

> Index of every page on this site: [llms.txt](https://neillin.com/llms.txt)

## Intro

This is my running checklist of modern CSS features—something I scan to decide which techniques to experiment with next. It's grouped by purpose (layout, selectors, color, typography, animation, forms, responsive, performance, functions & math), and each entry lists what it's for, an example, and browser support, plus whether I've already tried it.

The last section (K) is HTML rather than CSS. It lives in the same checklist because it's doing the same job: **turning things that used to need a pile of JavaScript into one declarative line**—and several entries are two halves of the same feature (`appearance: base-select` and `<selectedcontent>`, anchor positioning and popover, `reading-flow` and `focusgroup`), so splitting them apart would make the list harder to use, not easier.

## Legend

**Tried it**

- ✅ = I've experimented with it
- ⬜ = Not yet

**Support status** (as of October 2026; 🟠 / 🔴 move fast—re-check [caniuse](https://caniuse.com) / MDN before shipping)

- 🟢 Stable — broadly available across major browsers, safe for production
- 🟡 Newer — supported in most browsers; add a fallback
- 🟠 Experimental — only some browsers / behind a flag / just landed in Chrome
- 🔴 Proposed — still at the proposal stage, not usable in browsers yet

## A. Layout

<table>
<thead>
  <tr>
    <th>
      Property / Feature
    </th>
    
    <th>
      Main use & when to use
    </th>
    
    <th>
      Example
    </th>
    
    <th>
      Support
    </th>
    
    <th>
      Tried
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        grid-template-rows: masonry
      </code>
    </td>
    
    <td>
      Masonry (waterfall) layout without JS. WebKit's alternative, <code>
        display: grid-lanes
      </code>
      
      , now ships in Safari (Safari 27.2 Beta renames <code>
        flow-tolerance
      </code>
      
       to <code>
        fit-tolerance
      </code>
      
      ); the two approaches are still converging
    </td>
    
    <td>
      <code>
        grid-template-rows: masonry;
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        subgrid
      </code>
    </td>
    
    <td>
      Lets a child grid inherit the parent's tracks and gaps, so alignment snaps to the parent's lines; great for aligning elements across cards
    </td>
    
    <td>
      <code>
        grid-template-columns: subgrid;
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      Container Queries
    </td>
    
    <td>
      Responsive design based on the container's size (not the screen)—the key to true componentization
    </td>
    
    <td>
      <code>
        container-type: inline-size;
      </code>
      
       + <code>
        @container (width > 400px){}
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      Anchor Positioning
    </td>
    
    <td>
      Anchor one element's position to another (tooltip / popover / menu), replacing a lot of JS math
    </td>
    
    <td>
      <code>
        anchor-name: --a;
      </code>
      
       + <code>
        top: anchor(--a bottom);
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        @position-try
      </code>
    </td>
    
    <td>
      Fallback for anchor positioning: auto-flip when there isn't enough room
    </td>
    
    <td>
      <code>
        position-try-fallbacks: flip-block;
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reading-flow
      </code>
      
       / <code>
        reading-order
      </code>
    </td>
    
    <td>
      When flex/grid visual order is reordered, fix keyboard and screen-reader reading order (an accessibility must)
    </td>
    
    <td>
      <code>
        reading-flow: flex-visual;
      </code>
      
       / <code>
        reading-order: 1;
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      Gap Decorations (<code>
        row-rule
      </code>
      
       / <code>
        column-rule
      </code>
      
       / <code>
        rule
      </code>
      
      )
    </td>
    
    <td>
      Draw and style separators directly in grid/flex gaps—no more divider elements; plus fine-grain <code>
        rule-inset
      </code>
      
      /<code>
        rule-overlap
      </code>
      
      /<code>
        rule-visibility-items
      </code>
      
       (Chrome/Edge 149+; not in other browsers yet)
    </td>
    
    <td>
      <code>
        column-rule: 1px solid; row-rule: 1px solid;
      </code>
      
       or shorthand <code>
        rule: 1px solid;
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        margin-inline
      </code>
    </td>
    
    <td>
      Logical property; set both inline-axis margins at once (often <code>
        auto
      </code>
      
       to center)
    </td>
    
    <td>
      <code>
        margin-inline: auto;
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      Two-value display
    </td>
    
    <td>
      Write outer × inner display separately: <code>
        display: block flex
      </code>
      
       etc.; <code>
        flex
      </code>
      
       = <code>
        block flex
      </code>
      
      , <code>
        inline-flex
      </code>
      
       = <code>
        inline flex
      </code>
      
      . Clarifies display's two layers; single-value shorthands still fine day-to-day
    </td>
    
    <td>
      <code>
        display: inline flex;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        stretch
      </code>
      
       sizing keyword
    </td>
    
    <td>
      Make a box fill its container's available space (margins included), replacing vendor-specific values like <code>
        -webkit-fill-available
      </code>
      
       (see <a href="/en/blog/css-stretch/">
        my post testing it and checking my site
      </a>
      
      )
    </td>
    
    <td>
      <code>
        width: stretch;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      Single-axis scroll containers
    </td>
    
    <td>
      Scroll in one direction and <code>
        clip
      </code>
      
       in the other, so <code>
        position: sticky
      </code>
      
       can be constrained by different scroll containers per axis (e.g. a sticky table header and first column); Chrome 156 Beta
    </td>
    
    <td>
      <code>
        overflow: scroll clip;
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        safe
      </code>
      
       / <code>
        unsafe
      </code>
      
       overflow alignment
    </td>
    
    <td>
      When centered content doesn't fit, <code>
        safe
      </code>
      
       falls back to start alignment so content isn't pushed somewhere you can't see or scroll to; Safari 27.2 Beta adds pairing with <code>
        normal
      </code>
      
       and fixed-position support (see <a href="/en/blog/css-safe-alignment/">
        my post testing it with zoom and keyboard focus
      </a>
      
      )
    </td>
    
    <td>
      <code>
        align-items: safe center;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
</tbody>
</table>

## B. Selectors

<table>
<thead>
  <tr>
    <th>
      Property / Feature
    </th>
    
    <th>
      Main use & when to use
    </th>
    
    <th>
      Example
    </th>
    
    <th>
      Support
    </th>
    
    <th>
      Tried
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        :has()
      </code>
    </td>
    
    <td>
      The "parent selector" / select by descendant or sibling state—a logic powerhouse
    </td>
    
    <td>
      <code>
        .card:has(img){}
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ::part()
      </code>
    </td>
    
    <td>
      Style a specific element inside a Web Component from the outside (needs Shadow DOM knowledge)
    </td>
    
    <td>
      <code>
        my-el::part(label){}
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        :is()
      </code>
      
       / <code>
        :where()
      </code>
    </td>
    
    <td>
      Group selectors; <code>
        :where()
      </code>
      
       has 0 specificity (lower than inline), <code>
        :is()
      </code>
      
       takes its highest-specificity member
    </td>
    
    <td>
      <code>
        :is(h1,h2) :where(.x){}
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        nth-of
      </code>
      
       syntax
    </td>
    
    <td>
      <code>
        :nth-child(An+B of S)
      </code>
      
      —count the nth item within a filtered subset
    </td>
    
    <td>
      <code>
        :nth-child(2 of .active){}
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        :placeholder-shown
      </code>
    </td>
    
    <td>
      Style only while the placeholder is still showing (floating-label effect)
    </td>
    
    <td>
      <code>
        input:placeholder-shown{}
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        :in-range
      </code>
      
       / <code>
        :out-of-range
      </code>
    </td>
    
    <td>
      Style form values inside/outside their min/max range
    </td>
    
    <td>
      <code>
        input:out-of-range{}
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        :user-valid
      </code>
      
       / <code>
        :user-invalid
      </code>
    </td>
    
    <td>
      Show validation state only after the user has interacted—no angry red on load
    </td>
    
    <td>
      <code>
        input:user-invalid{}
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sibling-index()
      </code>
      
       / <code>
        sibling-count()
      </code>
    </td>
    
    <td>
      Get an element's index and total among siblings; enables staggered animation, dynamic widths (Baseline 2026)
    </td>
    
    <td>
      <code>
        --i: sibling-index();
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        :heading
      </code>
    </td>
    
    <td>
      Select all headings at once; supported from Safari 27, not in other browsers yet
    </td>
    
    <td>
      <code>
        :heading{}
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
  
  <tr>
    <td>
      Carousel selectors
    </td>
    
    <td>
      <code>
        ::scroll-marker
      </code>
      
       / <code>
        scroll-marker-group
      </code>
      
       / <code>
        :target-current
      </code>
      
       for native carousels and scrollspy; Chrome 154 adds <code>
        links
      </code>
      
       (default) and <code>
        tabs
      </code>
      
       modes to <code>
        scroll-marker-group
      </code>
      
      , changing the markers' focus order and ARIA semantics
    </td>
    
    <td>
      <code>
        :target-current{}
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      Media state pseudo-classes (<code>
        :playing
      </code>
      
       / <code>
        :paused
      </code>
      
       / <code>
        :muted
      </code>
      
      , etc.)
    </td>
    
    <td>
      Style <code>
        <video>
      </code>
      
      /<code>
        <audio>
      </code>
      
       directly by playing, paused, muted or buffering state, so custom players no longer need JS to toggle classes (Safari first, added in Chrome 156 Beta, not in Firefox yet)
    </td>
    
    <td>
      <code>
        video:paused + .play-btn{}
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        image-animation
      </code>
      
       / <code>
        :animated-image
      </code>
    </td>
    
    <td>
      Control whether animated images such as GIF and APNG play, and select animated images; animated GIFs have always been hard to square with WCAG 2.2.2 Pause, Stop, Hide, so this is high-value for accessibility (Chrome 156 Beta)
    </td>
    
    <td>
      <code>
        img:animated-image { image-animation: paused; }
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
</tbody>
</table>

## C. Color

<table>
<thead>
  <tr>
    <th>
      Property / Feature
    </th>
    
    <th>
      Main use & when to use
    </th>
    
    <th>
      Example
    </th>
    
    <th>
      Support
    </th>
    
    <th>
      Tried
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      New color functions (<code>
        oklch
      </code>
      
      -first)
    </td>
    
    <td>
      <code>
        hwb/lab/lch/color()
      </code>
      
       for wider gamuts; I've settled on <code>
        oklch
      </code>
      
      , which supports the <code>
        oklch(from …)
      </code>
      
       relative syntax
    </td>
    
    <td>
      <code>
        color: oklch(0.7 0.15 200 / 50%);
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        color-mix()
      </code>
    </td>
    
    <td>
      Mix two or more colors (best done in <code>
        oklch
      </code>
      
       space) for hover variants and transparent overlays; mixing three or more is currently Firefox 150 and Safari 27
    </td>
    
    <td>
      <code>
        color-mix(in oklch, red 40%, blue);
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contrast-color()
      </code>
    </td>
    
    <td>
      Automatically picks a readable foreground for a background (Baseline 2026). It only returns black or white; in my Chromium 153 tests it uses the WCAG 2 formula to pick the higher-contrast one, which mathematically is always at least 4.58:1, so AA is guaranteed but AAA isn't, and it can't pick brand colors
    </td>
    
    <td>
      <code>
        color: contrast-color(var(--bg));
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        accent-color
      </code>
    </td>
    
    <td>
      One line to re-theme checkbox/radio/range and other system controls
    </td>
    
    <td>
      <code>
        accent-color: rebeccapurple;
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        light-dark()
      </code>
    </td>
    
    <td>
      Give a property both a light and dark value at once; with <code>
        color-scheme
      </code>
      
       it skips the media query; it also accepts images (supported in all three major browsers)
    </td>
    
    <td>
      <code>
        color: light-dark(#000, #fff);
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        font-palette
      </code>
      
       / <code>
        @font-palette-values
      </code>
    </td>
    
    <td>
      Custom palettes for color (COLR) fonts
    </td>
    
    <td>
      <code>
        @font-palette-values --p{...}
      </code>
      
       + <code>
        font-palette: --p;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      Gradient interpolation color space
    </td>
    
    <td>
      <code>
        linear-gradient(in oklch …)
      </code>
      
       makes gradient transitions smoother and less muddy
    </td>
    
    <td>
      <code>
        background: linear-gradient(in oklch, #4ba3f7, #9d2398);
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        alpha()
      </code>
    </td>
    
    <td>
      Relative color function that changes only the opacity of an existing color, without rewriting the whole color value (Baseline 2026: Chrome 151, Firefox 155, Safari 27) (see <a href="/en/blog/css-alpha-revert-rule/">
        my post testing every color format and contrast
      </a>
      
      )
    </td>
    
    <td>
      <code>
        color: alpha(from var(--brand) / 50%);
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
</tbody>
</table>

## D. Typography

<table>
<thead>
  <tr>
    <th>
      Property / Feature
    </th>
    
    <th>
      Main use & when to use
    </th>
    
    <th>
      Example
    </th>
    
    <th>
      Support
    </th>
    
    <th>
      Tried
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        text-wrap: balance
      </code>
      
       / <code>
        pretty
      </code>
    </td>
    
    <td>
      <code>
        balance
      </code>
      
       evens out heading line widths; <code>
        pretty
      </code>
      
       avoids orphan words in body text (pretty is newer)
    </td>
    
    <td>
      <code>
        text-wrap: balance;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        text-decoration-skip-ink
      </code>
    </td>
    
    <td>
      Break the underline around descenders (g, y) for a cleaner look; Chrome 155 Beta adds <code>
        text-decoration-skip-spaces
      </code>
      
       to control whether the underline skips spaces
    </td>
    
    <td>
      <code>
        text-decoration-skip-ink: auto;
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        text-decoration-inset
      </code>
    </td>
    
    <td>
      Shorten or extend decorations such as underlines; positive values inset, negative values outset, for underline animations without extra elements (Chrome 154)
    </td>
    
    <td>
      <code>
        text-decoration-inset: 0.5em;
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        text-combine-upright
      </code>
    </td>
    
    <td>
      Lay numbers/Latin horizontally within vertical text ("tate-chu-yoko"); common in CJK long-form
    </td>
    
    <td>
      <code>
        text-combine-upright: all;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        text-emphasis
      </code>
    </td>
    
    <td>
      Emphasis dots/circles that track the character center; common CJK annotation
    </td>
    
    <td>
      <code>
        text-emphasis: dot;
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ruby-align
      </code>
    </td>
    
    <td>
      Alignment of ruby annotations (bopomofo / pinyin, etc.)
    </td>
    
    <td>
      <code>
        ruby-align: center;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        paint-order
      </code>
    </td>
    
    <td>
      Control the paint order of text fill vs. stroke (for outlined text)
    </td>
    
    <td>
      <code>
        paint-order: stroke fill;
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        box-decoration-break: clone
      </code>
    </td>
    
    <td>
      On line/page breaks, apply border/radius/background to each fragment; especially nice for link focus
    </td>
    
    <td>
      <code>
        box-decoration-break: clone;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        text-box-trim
      </code>
    </td>
    
    <td>
      Trim the extra space above/below a font for precise vertical alignment (Chrome and Safari; not in Firefox yet)
    </td>
    
    <td>
      <code>
        text-box: trim-both cap alphabetic;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        line-clamp
      </code>
      
       (<code>
        -webkit-line-clamp
      </code>
      
      )
    </td>
    
    <td>
      Show "…" after N lines; the new standard <code>
        line-clamp
      </code>
      
       is gradually replacing the webkit form
    </td>
    
    <td>
      <code>
        -webkit-line-clamp: 3;
      </code>
      
       (needs <code>
        -webkit-box
      </code>
      
      )
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        hanging-punctuation
      </code>
    </td>
    
    <td>
      Hang leading/trailing punctuation outside the edge for tidier alignment (Safari-first)
    </td>
    
    <td>
      <code>
        hanging-punctuation: first last;
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        font-variant-numeric: tabular-nums
      </code>
    </td>
    
    <td>
      Monospaced digits—essential for timers/prices/percentages that jitter (font must support it)
    </td>
    
    <td>
      <code>
        font-variant-numeric: tabular-nums;
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        lh
      </code>
      
       unit
    </td>
    
    <td>
      Set margin/spacing in line-height units so they scale with font size
    </td>
    
    <td>
      <code>
        margin-bottom: 1.5lh;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        margin-trim
      </code>
    </td>
    
    <td>
      Trim margins of the first/last children in a container, avoiding <code>
        :first/:last-child
      </code>
      
       resets (Safari-first; added in Chrome 155 Beta)
    </td>
    
    <td>
      <code>
        margin-trim: block;
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        text-fit
      </code>
    </td>
    
    <td>
      Auto-scales font size so text exactly fills its container's width—responsive headlines without manual math or JS (new in Chrome 150; always add a percentage limit, or zooming makes the text smaller—see <a href="/en/blog/css-text-fit/">
        my tests
      </a>
      
      )
    </td>
    
    <td>
      <code>
        h1 { text-fit: grow per-line-all 200%; }
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        text-autospace
      </code>
    </td>
    
    <td>
      Automatically adds proper spacing between CJK text and Latin letters or numbers, so you don't have to type the spaces by hand; Safari 27 adds the <code>
        insert
      </code>
      
       value
    </td>
    
    <td>
      <code>
        text-autospace: normal;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        font-width
      </code>
    </td>
    
    <td>
      The new canonical name for <code>
        font-stretch
      </code>
      
      , selecting condensed or expanded faces; the old name stays as an alias (Baseline 2026)
    </td>
    
    <td>
      <code>
        font-width: 75%;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
</tbody>
</table>

## E. Animation & Transition

<table>
<thead>
  <tr>
    <th>
      Property / Feature
    </th>
    
    <th>
      Main use & when to use
    </th>
    
    <th>
      Example
    </th>
    
    <th>
      Support
    </th>
    
    <th>
      Tried
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Scroll-driven animation (formerly "@scroll-timeline")
    </td>
    
    <td>
      Drive animation by scroll progress instead of time; the spec is now <code>
        animation-timeline: scroll()/view()
      </code>
    </td>
    
    <td>
      <code>
        animation-timeline: scroll();
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        @view-transition
      </code>
      
       / <code>
        transition-behavior
      </code>
    </td>
    
    <td>
      Transitions for page/state changes; <code>
        allow-discrete
      </code>
      
       lets discrete properties like <code>
        display
      </code>
      
       transition
    </td>
    
    <td>
      <code>
        transition-behavior: allow-discrete;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        @starting-style
      </code>
    </td>
    
    <td>
      Define an element's first-appearance start styles; enables <code>
        display:none → shown
      </code>
      
       entry animations
    </td>
    
    <td>
      <code>
        @starting-style{ opacity:0; }
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        backface-visibility
      </code>
    </td>
    
    <td>
      Whether the back face shows during a 3D flip (card-flip effect)
    </td>
    
    <td>
      <code>
        backface-visibility: hidden;
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        prefers-reduced-motion
      </code>
    </td>
    
    <td>
      Detect the reduced-motion preference, an accessibility must; pairs with <code>
        prefers-color-scheme
      </code>
      
       for light/dark
    </td>
    
    <td>
      <code>
        @media (prefers-reduced-motion: reduce){}
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
</tbody>
</table>

## F. Forms & Components

<table>
<thead>
  <tr>
    <th>
      Property / Feature
    </th>
    
    <th>
      Main use & when to use
    </th>
    
    <th>
      Example
    </th>
    
    <th>
      Support
    </th>
    
    <th>
      Tried
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        field-sizing: content
      </code>
    </td>
    
    <td>
      Let input/textarea grow automatically to fit their content (Baseline 2026)
    </td>
    
    <td>
      <code>
        field-sizing: content;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      Customizable <code>
        <select>
      </code>
      
       (<code>
        appearance: base-select
      </code>
      
      )
    </td>
    
    <td>
      Fully style the native dropdown; options can hold icons/HTML. Pair it with <code>
        ::picker(select)
      </code>
      
       and <code>
        ::picker-icon
      </code>
      
       to style the popup, and <code>
        <selectedcontent>
      </code>
      
       to clone the chosen option. You finally don't have to rebuild a select out of divs just to style it — and rebuilding it is a classic source of accessibility disasters (Chrome 135 and Safari 27; not in Firefox yet)
    </td>
    
    <td>
      <code>
        select{ appearance: base-select; }
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        <selectlist>
      </code>
      
       (formerly <code>
        <selectmenu>
      </code>
      
      )
    </td>
    
    <td>
      A highly customizable dropdown component; renamed and folded into the "customizable select" track
    </td>
    
    <td>
      <code>
        <selectlist>…</selectlist>
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ::backdrop
      </code>
    </td>
    
    <td>
      Style the layer behind <code>
        dialog.showModal()
      </code>
      
       or fullscreen
    </td>
    
    <td>
      <code>
        dialog::backdrop{}
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
</tbody>
</table>

## G. Responsive & Preferences

<table>
<thead>
  <tr>
    <th>
      Property / Feature
    </th>
    
    <th>
      Main use & when to use
    </th>
    
    <th>
      Example
    </th>
    
    <th>
      Support
    </th>
    
    <th>
      Tried
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Media query range syntax
    </td>
    
    <td>
      Write breakpoints with <code>
        <=
      </code>
      
      /<code>
        >=
      </code>
      
      , skipping the <code>
        min-width
      </code>
      
       + <code>
        320.01px
      </code>
      
       pain
    </td>
    
    <td>
      <code>
        @media (width >= 320px){}
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        prefers-color-scheme
      </code>
    </td>
    
    <td>
      Detect dark/light theme preference
    </td>
    
    <td>
      <code>
        @media (prefers-color-scheme: dark){}
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        prefers-contrast
      </code>
    </td>
    
    <td>
      Detect a request for more/less contrast
    </td>
    
    <td>
      <code>
        @media (prefers-contrast: more){}
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        forced-colors
      </code>
    </td>
    
    <td>
      Adjust for high-contrast / forced-colors mode (Windows High Contrast)
    </td>
    
    <td>
      <code>
        @media (forced-colors: active){}
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        resolution
      </code>
      
       media
    </td>
    
    <td>
      Switch by output device pixel density (e.g. Retina)
    </td>
    
    <td>
      <code>
        @media (resolution >= 2dppx){}
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      Style Queries <code>
        @container style()
      </code>
    </td>
    
    <td>
      Style by a container's custom-property value (e.g. theme); great for component variants
    </td>
    
    <td>
      <code>
        @container style(--theme: dark){}
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      Scroll-State Queries
    </td>
    
    <td>
      Style by a container's scroll state (e.g. <code>
        stuck
      </code>
      
      , <code>
        snapped
      </code>
      
      ); can detect whether a sticky element is stuck
    </td>
    
    <td>
      <code>
        @container scroll-state(stuck: top){}
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
</tbody>
</table>

## H. Encapsulation & Performance

<table>
<thead>
  <tr>
    <th>
      Property / Feature
    </th>
    
    <th>
      Main use & when to use
    </th>
    
    <th>
      Example
    </th>
    
    <th>
      Support
    </th>
    
    <th>
      Tried
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Cascade Layers <code>
        @layer
      </code>
    </td>
    
    <td>
      Manage priority with layers to tame specificity in large projects
    </td>
    
    <td>
      <code>
        @layer base, components, utilities;
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        revert-rule
      </code>
    </td>
    
    <td>
      Roll a property back to the value it would have if the current rule didn't exist; the same family as <code>
        revert
      </code>
      
       (back to browser defaults) and <code>
        revert-layer
      </code>
      
       (back to the previous <code>
        @layer
      </code>
      
      ) (Baseline 2026) (see <a href="/en/blog/css-alpha-revert-rule/">
        my post comparing it with revert and revert-layer
      </a>
      
      )
    </td>
    
    <td>
      <code>
        color: revert-rule;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        @scope
      </code>
    </td>
    
    <td>
      Scope styles to a block with an optional lower bound, similar to CSS Modules scoping
    </td>
    
    <td>
      <code>
        @scope (.card) to (.content){}
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contain
      </code>
    </td>
    
    <td>
      Declare inner layout/style independence to isolate reflow and boost performance
    </td>
    
    <td>
      <code>
        contain: layout style;
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contain-intrinsic-size
      </code>
    </td>
    
    <td>
      With <code>
        content-visibility: auto
      </code>
      
      , give an estimated size first to avoid scroll jumps; switches to auto once cached
    </td>
    
    <td>
      <code>
        contain-intrinsic-size: auto 100px;
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        scrollbar-gutter: stable
      </code>
    </td>
    
    <td>
      Reserve the scrollbar gutter so content doesn't shift when the scrollbar appears
    </td>
    
    <td>
      <code>
        scrollbar-gutter: stable;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        scrollbar-color
      </code>
      
       / <code>
        scrollbar-width
      </code>
    </td>
    
    <td>
      Customize scrollbar color and thickness
    </td>
    
    <td>
      <code>
        scrollbar-color: #888 #eee;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        @supports
      </code>
    </td>
    
    <td>
      Feature detection for progressive enhancement and fallbacks
    </td>
    
    <td>
      <code>
        @supports (display: grid){}
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        at-rule()
      </code>
    </td>
    
    <td>
      Test inside <code>
        @supports
      </code>
      
       whether an at-rule such as <code>
        @scope
      </code>
      
       or <code>
        @position-try
      </code>
      
       is supported, instead of guessing indirectly (Firefox 157+)
    </td>
    
    <td>
      <code>
        @supports at-rule(@scope){}
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
</tbody>
</table>

## I. Functions & Math

<table>
<thead>
  <tr>
    <th>
      Property / Feature
    </th>
    
    <th>
      Main use & when to use
    </th>
    
    <th>
      Example
    </th>
    
    <th>
      Support
    </th>
    
    <th>
      Tried
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        round()
      </code>
      
       / <code>
        mod()
      </code>
      
       / <code>
        rem()
      </code>
    </td>
    
    <td>
      Rounding and remainders in CSS, to align to a grid/rhythm
    </td>
    
    <td>
      <code>
        width: round(down, 15.5px, 4px);
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      Trig functions <code>
        sin/cos/tan
      </code>
    </td>
    
    <td>
      Circular layouts, waveforms, angle math
    </td>
    
    <td>
      <code>
        width: calc(sin(30deg) * 100px);
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        calc-size()
      </code>
      
       / <code>
        interpolate-size
      </code>
    </td>
    
    <td>
      Animate transitions to keywords like <code>
        auto
      </code>
      
      /<code>
        min-content
      </code>
      
      , e.g. an accordion expanding to an unknown height; combined with <code>
        round()
      </code>
      
      , it can also make a height an exact multiple of a background pattern so the pattern isn't cut off (<code>
        height: calc-size(auto, round(up, size, 48px))
      </code>
      
      )
    </td>
    
    <td>
      <code>
        interpolate-size: allow-keywords;
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        random()
      </code>
    </td>
    
    <td>
      Native random values in CSS (scatter, jitter effects)
    </td>
    
    <td>
      <code>
        rotate: random(-5deg, 5deg);
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        if()
      </code>
    </td>
    
    <td>
      Conditional logic inside a property value (without <code>
        else
      </code>
      
      , the property falls back to its initial value and a focus outline can disappear entirely; see <a href="/en/blog/css-if-function/">
        this post
      </a>
      
      )
    </td>
    
    <td>
      <code>
        display: if(style(--open: 1): block; else: none);
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        @function
      </code>
    </td>
    
    <td>
      Custom CSS functions / a mixin-like concept, with parameters and a return value (see <a href="/en/blog/css-if-function/">
        this post
      </a>
      
       for using one to guarantee a minimum target size)
    </td>
    
    <td>
      <code>
        @function --double(--x){ result: calc(var(--x)*2); }
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        progress()
      </code>
    </td>
    
    <td>
      Returns where a value sits between two others as a 0–1 ratio, for styles that change continuously with size (Baseline 2026; Firefox 155 and Safari 27 also support <code>
        no-clamp
      </code>
      
      , letting the result go outside 0–1) (applied to this site's fluid h1 and h2 sizes so headings also reach 2× at 200% zoom)
    </td>
    
    <td>
      <code>
        opacity: progress(100cqw, 300px, 900px);
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        attr()
      </code>
      
       in any property
    </td>
    
    <td>
      <code>
        attr()
      </code>
      
       used to work only in <code>
        content
      </code>
      
      ; now it can read an HTML attribute with a type and use it as the value of any property, such as a width or color (Chrome first, added in Firefox 155; see <a href="/en/blog/css-attr/">
        my post on reading ARIA attributes with it
      </a>
      
      )
    </td>
    
    <td>
      <code>
        width: attr(data-w type(<length>));
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        symbols()
      </code>
    </td>
    
    <td>
      Define list markers directly in CSS without a separate <code>
        @counter-style
      </code>
      
       (Chrome 155 Beta)
    </td>
    
    <td>
      <code>
        list-style: symbols(cyclic "◆" "◇");
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
</tbody>
</table>

## J. Misc

<table>
<thead>
  <tr>
    <th>
      Property / Feature
    </th>
    
    <th>
      Main use & when to use
    </th>
    
    <th>
      Example
    </th>
    
    <th>
      Support
    </th>
    
    <th>
      Tried
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Native Nesting
    </td>
    
    <td>
      Sass/SCSS-style nesting without a preprocessor
    </td>
    
    <td>
      <code>
        .card{ & .title{} }
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        <img loading="lazy">
      </code>
    </td>
    
    <td>
      Lazy-load images to improve first-paint performance
    </td>
    
    <td>
      <code>
        <img loading="lazy">
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        overscroll-behavior: contain
      </code>
    </td>
    
    <td>
      Stop a scrolled-to-the-end block from scrolling the outer container (common for modals/sidebars)
    </td>
    
    <td>
      <code>
        overscroll-behavior: contain;
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        object-view-box
      </code>
    </td>
    
    <td>
      Crop a region of an image directly in CSS, no separate cropped file needed
    </td>
    
    <td>
      <code>
        object-view-box: inset(10% 10% 10% 10%);
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      Responsive iframes (<code>
        frame-sizing
      </code>
      
      )
    </td>
    
    <td>
      An iframe sizes its height to the embedded content, with no more <code>
        postMessage
      </code>
      
       height plumbing; the embedded page opts in with <code>
        <meta name="responsive-embedded-sizing">
      </code>
      
       (Chrome 154)
    </td>
    
    <td>
      <code>
        iframe { frame-sizing: content-height; }
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        scroll-snap-type: pair
      </code>
    </td>
    
    <td>
      A new scroll snapping mode (Chrome 156 Beta); I'll test the details once it ships to stable
    </td>
    
    <td>
      <code>
        scroll-snap-type: pair;
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
  
  <tr>
    <td>
      JPEG XL (<code>
        image/jxl
      </code>
      
      )
    </td>
    
    <td>
      A newer image format that compresses better than JPEG and can losslessly convert existing JPEGs; Safari supports it, and Chrome 155 Beta adds decoding
    </td>
    
    <td>
      <code>
        <source type="image/jxl" srcset="a.jxl">
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
  
  <tr>
    <td>
      Individual transform properties
    </td>
    
    <td>
      <code>
        translate
      </code>
      
      /<code>
        rotate
      </code>
      
      /<code>
        scale
      </code>
      
       as their own properties, easier to animate separately
    </td>
    
    <td>
      <code>
        rotate: 45deg; scale: 1.2;
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        border-image
      </code>
    </td>
    
    <td>
      Complex borders from a sliced image, avoiding traditional slicing
    </td>
    
    <td>
      <code>
        border-image: url(frame.png) 30 round;
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        background-clip: border-area
      </code>
    </td>
    
    <td>
      Clips the background to the area painted by the border strokes (respecting <code>
        border-width
      </code>
      
      /<code>
        border-style
      </code>
      
      , ignoring <code>
        border-color
      </code>
      
       transparency), so gradient borders work natively instead of via <code>
        border-image
      </code>
      
       workarounds (new in Chrome 150) (tested: forced colors mode drops the gradient, but the browser turns the transparent border into the text color, so the border shape stays visible)
    </td>
    
    <td>
      <code>
        border: 3px solid transparent; background: linear-gradient(45deg, red, blue); background-clip: border-area;
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        corner-shape
      </code>
    </td>
    
    <td>
      Corner shapes beyond <code>
        border-radius
      </code>
      
       (squircle / notched, etc.), used together with <code>
        border-radius
      </code>
      
      ; Chrome 156 Beta adds the <code>
        corner
      </code>
      
       shorthand (tested with an app icon, coupon, step arrows and cut-corner button; see <a href="/en/blog/css-corner-shape/">
        this post
      </a>
      
      )
    </td>
    
    <td>
      <code>
        corner-shape: squircle; border-radius: 30px;
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      Font smoothing (<code>
        -webkit-font-smoothing
      </code>
      
      )
    </td>
    
    <td>
      The key to non-harsh text in dark mode: on macOS, light text on a dark background looks bold and glowing due to subpixel antialiasing; grayscale antialiasing makes it thinner and gentler. Non-standard, works only on certain platforms
    </td>
    
    <td>
      <code>
        -webkit-font-smoothing: antialiased;
      </code>
      
       (+ <code>
        -moz-osx-font-smoothing: grayscale;
      </code>
      
      )
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        @when
      </code>
      
       / <code>
        @else
      </code>
    </td>
    
    <td>
      CSS if/else conditional blocks; still a proposal, unusable in any browser
    </td>
    
    <td>
      <code>
        @when supports(...){} @else{}
      </code>
    </td>
    
    <td>
      🔴
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      Scroll anchoring (<code>
        overflow-anchor
      </code>
      
      )
    </td>
    
    <td>
      When content loads or is inserted above the viewport, the browser keeps your reading position steady instead of jumping; on by default, opt out per element with <code>
        none
      </code>
      
      . Those jumps are especially disorienting for people with cognitive or motor disabilities (with Safari 27, all three engines support it)
    </td>
    
    <td>
      <code>
        overflow-anchor: none;
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
</tbody>
</table>

## K. HTML Elements & Attributes (Not CSS, but the Same "Declarative Instead of JS" Trend)

Strictly speaking this section isn't CSS, but it points the same way modern CSS does: **taking things that used to need a pile of JavaScript and making them declarative** — and most of them affect accessibility quality directly, so they belong in the same checklist.

### K-1. New HTML elements

<table>
<thead>
  <tr>
    <th>
      Element
    </th>
    
    <th>
      Main use & when to use
    </th>
    
    <th>
      Example
    </th>
    
    <th>
      Support
    </th>
    
    <th>
      Tried
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        <geolocation>
      </code>
    </td>
    
    <td>
      A declarative button for location requests: the browser owns the permission flow and — crucially — offers a recovery path for users who previously denied access (which used to be a dead end). Degrades to a <code>
        <span>
      </code>
      
       where unsupported, so it progressively enhances (tested: the browser only compares the button's own text and background colors and disables it below 3:1, but background images, blur and a removed focus outline all get through)
    </td>
    
    <td>
      <code>
        <geolocation onlocation="fn(event)">
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        <usermedia>
      </code>
    </td>
    
    <td>
      Declarative camera/microphone access that hands the page a <code>
        MediaStream
      </code>
      
       directly, with no <code>
        getUserMedia()
      </code>
      
       call of your own, and lets people who blocked access recover right on the page. Video-only <code>
        <camera>
      </code>
      
       and audio-only <code>
        <microphone>
      </code>
      
       variants shipped in Chrome 153 (in my tests, <code>
        lang="zh-Hant-TW"
      </code>
      
       shows Simplified Chinese, there's no state once it's on, and keyboard users who press too quickly get a silent failure—see <a href="/en/blog/html-usermedia/">
        my post
      </a>
      
      )
    </td>
    
    <td>
      <code>
        <usermedia>
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        <install>
      </code>
    </td>
    
    <td>
      An install button for PWAs whose label and appearance the browser controls (users who click "Install" aren't surprised by what happens next). Point <code>
        installurl
      </code>
      
       elsewhere to install apps from other origins — enough to build a catalogue page
    </td>
    
    <td>
      <code>
        <install installurl="…" manifestid="…">
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        <model>
      </code>
    </td>
    
    <td>
      Embed an interactive 3D model (USDZ) as easily as an <code>
        <img>
      </code>
      
      ; supply multiple formats via <code>
        <source>
      </code>
      
       and custom lighting via <code>
        environmentmap
      </code>
    </td>
    
    <td>
      <code>
        <model src="a.usdz">
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
</tbody>
</table>

### K-2. New HTML attributes & behaviours

<table>
<thead>
  <tr>
    <th>
      Property / Feature
    </th>
    
    <th>
      Main use & when to use
    </th>
    
    <th>
      Example
    </th>
    
    <th>
      Support
    </th>
    
    <th>
      Tried
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        focusgroup
      </code>
    </td>
    
    <td>
      Declaratively gives composite widgets (toolbars, tab lists, menus) arrow-key navigation, a guaranteed tab stop, and last-focused memory — exactly the WAI-ARIA keyboard pattern you previously had to hand-roll with roving tabindex (new in Chrome 150; it needs a behavior type, a bare <code>
        focusgroup
      </code>
      
       does nothing, see <a href="/en/blog/focusgroup/">
        my test post
      </a>
      
      )
    </td>
    
    <td>
      <code>
        <div focusgroup="toolbar">…</div>
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      Invoker Commands (<code>
        command
      </code>
      
       / <code>
        commandfor
      </code>
      
      )
    </td>
    
    <td>
      Control a popover/dialog with declarative HTML buttons, no scripting. Landed stable: <code>
        show-modal
      </code>
      
      , <code>
        close
      </code>
      
      , <code>
        request-close
      </code>
      
      , <code>
        toggle-popover
      </code>
      
      , <code>
        show-popover
      </code>
      
      , <code>
        hide-popover
      </code>
      
       (Baseline 2025; more coming — media controls, copy text, etc.)
    </td>
    
    <td>
      <code>
        <button command="show-modal" commandfor="dlg">Open</button>
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      Interest Invokers
    </td>
    
    <td>
      The same command mechanism, but triggered by "showing interest" (hover/focus) rather than a click — enough to build a native tooltip with no JS
    </td>
    
    <td>
      <code>
        <button interestfor="tip">
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        hidden="until-found"
      </code>
    </td>
    
    <td>
      Content stays collapsed but is still reachable by in-page search, and expands automatically when matched. The right way to collapse long-form sections and FAQs without making their content unfindable
    </td>
    
    <td>
      <code>
        <div hidden="until-found">
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        popover="hint"
      </code>
    </td>
    
    <td>
      A popover category meant for tooltips: it keeps light-dismiss, but only closes other hints instead of tearing down your main popover with it
    </td>
    
    <td>
      <code>
        <div popover="hint">
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sizes="auto"
      </code>
    </td>
    
    <td>
      Stop hand-computing <code>
        sizes
      </code>
      
       for responsive images and let the browser work it out; pairs with <code>
        srcset
      </code>
      
       and <code>
        loading="lazy"
      </code>
      
       (now in Chrome, Firefox and Safari 27) (see <a href="/en/blog/html-sizes-auto/">
        my post testing it and fixing my portfolio
      </a>
      
      )
    </td>
    
    <td>
      <code>
        <img srcset="…" sizes="auto">
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      Declarative Shadow DOM
    </td>
    
    <td>
      Build a shadow root with no JavaScript, so SSR output can carry it
    </td>
    
    <td>
      <code>
        <template shadowrootmode="open">
      </code>
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        Element.setHTML()
      </code>
    </td>
    
    <td>
      A safe <code>
        innerHTML
      </code>
      
      : inserts markup while stripping <code>
        <script>
      </code>
      
      , event attributes and other dangerous markup (Sanitizer API); the counterpart to the <code>
        setHTMLUnsafe()
      </code>
      
       mentioned in my Declarative Shadow DOM post. Firefox 157 now sanitizes while parsing; check caniuse for other browsers (in my tests the default config strips every <code>
        aria-*
      </code>
      
       and <code>
        role
      </code>
      
      ; see <a href="/en/blog/html-sethtml/">
        this post
      </a>
      
      )
    </td>
    
    <td>
      <code>
        el.setHTML(userInput);
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        shadowrootreferencetarget
      </code>
    </td>
    
    <td>
      Lets a <code>
        <label>
      </code>
      
       or <code>
        aria-*
      </code>
      
       outside the shadow root point at the real input inside it — the long-standing labelling problem for web components (see <a href="/en/blog/shadow-dom-reference-target/">
        my post testing it, with a UI Kit example
      </a>
      
      )
    </td>
    
    <td>
      <code>
        <template shadowrootmode="open" shadowrootreferencetarget="real-input">
      </code>
    </td>
    
    <td>
      🟠
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        <h1>
      </code>
      
       nested sizing fix
    </td>
    
    <td>
      UA stylesheet change: an <code>
        <h1>
      </code>
      
       inside a <code>
        <section>
      </code>
      
       is no longer shrunk automatically, so heading hierarchy finally renders predictably (see <a href="/en/blog/html-nested-h1/">
        my post testing it and fixing my site's headings
      </a>
      
      )
    </td>
    
    <td>
      —
    </td>
    
    <td>
      🟢
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ariaNotify()
      </code>
    </td>
    
    <td>
      Ask the screen reader to announce a message directly (e.g. "Added to cart"), replacing the old trick of hiding an <code>
        aria-live
      </code>
      
       region and stuffing text into it. It's a DOM API rather than an HTML attribute, but what it replaces is exactly that HTML-attribute pattern (Chrome 141 and Firefox 150 onward; sources disagree on Safari, so test it yourself)
    </td>
    
    <td>
      <code>
        document.ariaNotify("Added to cart");
      </code>
    </td>
    
    <td>
      🟡
    </td>
    
    <td>
      ✅
    </td>
  </tr>
</tbody>
</table>

### K-3. Proposal / prototype stage (just worth knowing about)

<table>
<thead>
  <tr>
    <th>
      Feature
    </th>
    
    <th>
      Main use
    </th>
    
    <th>
      Support
    </th>
    
    <th>
      Tried
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Declarative Partial Updates
    </td>
    
    <td>
      Streaming partial HTML updates that inject content without a navigation; a native <code>
        <include>
      </code>
      
       element may follow
    </td>
    
    <td>
      🔴
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        <persistentwidget>
      </code>
    </td>
    
    <td>
      Embedded content that survives same-origin navigations (a player that doesn't stop, for instance)
    </td>
    
    <td>
      🔴
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
  
  <tr>
    <td>
      HTML-in-Canvas (<code>
        layoutsubtree
      </code>
      
      )
    </td>
    
    <td>
      Render interactive HTML onto a canvas
    </td>
    
    <td>
      🔴
    </td>
    
    <td>
      ⬜
    </td>
  </tr>
</tbody>
</table>

## What to try next (recommended)

Everything that used to be listed here is now checked off. These are the unchecked items I want to do next: both need Chrome 156 stable (in the 153 I tested, the `clip` in `overflow: scroll clip` still turns into `hidden`), and the animated-image one actually has the highest accessibility value.

1. Single-axis scroll containers (`overflow: scroll clip`)—a data table with both the header row and first column sticky; can it be scrolled with the keyboard?
2. `image-animation` / `:animated-image`—lets animated GIFs be paused, mapping directly to WCAG 2.2.2.

> **Note:** Most items marked 🟠 / 🔴 only landed in Chrome in 2025–2026 or are still proposals, and support changes every quarter. Before shipping to production, treat [caniuse.com](https://caniuse.com) and MDN as the source of truth, and remember to add an `@supports` fallback for new features.

## References

- [Can I use (browser support lookup)](https://caniuse.com)
- [MDN Web Docs — CSS](https://developer.mozilla.org/en-US/docs/Web/CSS)
- [web.dev — Learn CSS](https://web.dev/learn/css)
- [Chrome for Developers — CSS](https://developer.chrome.com/tag/css)
- [New in Chrome 150 (`text-fit`, `background-clip: border-area`, `focusgroup`)](https://developer.chrome.com/blog/new-in-chrome-150)
- [CSS Gap Decorations Now Available (`row-rule`/`column-rule`/`rule`, CSS-Tricks)](https://css-tricks.com/css-gap-decorations-now-available/)
- [New Things You Should Know About HTML Here in Mid 2026 (source for the newly added section K entries)](https://blog.master.dev/new-things-you-should-know-about-html-here-in-mid-2026)
- [Chrome for Developers — the `<geolocation>` element](https://developer.chrome.com/blog/geolocation-html-element)
- [Chrome for Developers — the `<usermedia>` element](https://developer.chrome.com/blog/usermedia-html-element)
- [Chrome for Developers — the `<install>` element (origin trial)](https://developer.chrome.com/blog/install-element-ot)
- [Apple WWDC26 — Get started with the HTML Model element](https://developer.apple.com/videos/play/wwdc2026/215/)
- [web.dev — New to the web platform in September 2026 (source for the October update)](https://web.dev/blog/web-platform-09-2026)
- [Safari 27 Release Notes (Apple; one of the sources for this support update)](https://developer.apple.com/documentation/safari-release-notes/safari-27-release-notes)
- [Web platform features explorer (Baseline status lookup)](https://web-platform-dx.github.io/web-features-explorer/)
- [CSS-Tricks](https://css-tricks.com)

## Sitemap

See the full [sitemap](https://neillin.com/sitemap.md) for all pages.
