196 features · 77 demos written for this site · the rest illustrated by MDN
Modern CSS, live.
Every CSS feature that reached Baseline, or shipped in a browser engine, in 2023 or later, as
web-features names and describes it. Each one renders below, in your browser,
with the code to edit and copy. Demos written for this site say so in their window bar; the others are MDN's own examples.
Newly available
Baseline newly available: supported by the latest version of every major browser. Safe to use with a fallback for older versions.
<div class="sda"> <p class="unsupported" role="note">Your browser does not support scroll-driven animations. The cards below stay visible and static.</p> <div class="sda-scroller" tabindex="0" role="region" aria-label="Scrollable cards"> <header class="sda-head"> <h1>Scroll inside this box</h1> <div class="sda-bar" aria-hidden="true"></div> </header> <ol class="sda-list"> <li class="sda-card"><span class="sda-num">1</span><div><h2>Driven by scroll</h2><p>The bar above grows as you scroll.</p></div></li> <li class="sda-card"><span class="sda-num">2</span><div><h2>No JavaScript</h2><p>Each card is animated by its own position.</p></div></li> <li class="sda-card"><span class="sda-num">3</span><div><h2>Scrub both ways</h2><p>Scroll back up and the cards leave again.</p></div></li> <li class="sda-card"><span class="sda-num">4</span><div><h2>Runs off the main thread</h2><p>Smooth even when the page is busy.</p></div></li> <li class="sda-card"><span class="sda-num">5</span><div><h2>One timeline each</h2><p>scroll() follows the box, view() follows the card.</p></div></li> <li class="sda-card"><span class="sda-num">6</span><div><h2>The end</h2><p>The bar is now full.</p></div></li> </ol> </div></div>
Browser support
First browser version supporting the whole Scroll-driven animations feature
Chrome
115
Edge
115
Firefox
159
Safari
26
Chrome Android
115
Safari iOS
26
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The animation property of an AnimationEvent or TransitionEvent object is the Animation object that represents the animation (and thus the element) that fired an animation event.
No demo written yet and no MDN example for this feature: read its definition through the links below.
Browser support
First browser version supporting the whole Animation accessors feature
Chrome
151
Edge
151
Firefox
152
Safari
27
Chrome Android
151
Safari iOS
27
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The light-dark() CSS function accepts, in addition to colors, two <image> values, such as a gradient or URL, and uses one depending on the current color scheme.
Live previewExample from MDN
:root { /* this has to be set to switch between light or dark */ color-scheme: light dark; --light-bg: ghostwhite; --light-color: darkslategray; --light-code: tomato; --dark-bg: darkslategray; --dark-color: ghostwhite; --dark-code: gold;}* { background-color: light-dark(var(--light-bg), var(--dark-bg)); color: light-dark(var(--light-color), var(--dark-color));}code { color: light-dark(var(--light-code), var(--dark-code));}.light { /* forces light color-scheme */ color-scheme: light;}.dark { /* forces dark color-scheme */ color-scheme: dark;}section { padding: 0.8rem;}
<h1><code>light-dark()</code> CSS function</h1><section> <h2>Automatic</h2> <p>This section will react to the users system or user agent setting.</p></section><section class="light"> <h2>Light</h2> <p> This section will be light due to the <code>color-scheme: light;</code>. </p></section><section class="dark"> <h2>Dark</h2> <p>This section will be dark due to the <code>color-scheme: dark;</code>.</p></section>
web-features The overflow-anchor CSS property sets an element as a possible scroll anchor, reducing unintended scrolling when document changes occur above the current scrollport. This is enabled by default where supported.
Newly available since September 2026Explicit defaults
web-features The revert-rule CSS keyword resets a property to its previous value in the cascade, as if the current style rule had not been present. It's especially useful with conditionals, to cancel a declaration when the condition is not met.
No demo written yet and no MDN example for this feature: read its definition through the links below.
Browser support
First browser version supporting the whole revert-rule feature
Chrome
148
Edge
148
Firefox
150
Safari
27
Chrome Android
148
Safari iOS
27
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The progress() CSS function returns a ratio for the relative position of one value between two other values, clamped between 0 and 1. You can use it to interpolate a value for other calculations.
progress()Written for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-pg"> <p class="unsupported">This browser does not support progress(), so the bars and the text do not follow the controls.</p> <p class="hint">Drag the slider, then drag the corner of the dashed box. progress() turns any value into a ratio from 0 to 1.</p> <div class="controls"> <label for="v">Value</label> <input type="range" id="v" min="0" max="100" value="50"> <output id="out" for="v">50</output> </div> <p class="label"><code>progress(value, 20, 80)</code>: 0 below 20, 1 above 80.</p> <div class="meter"><div class="fill"></div></div> <p class="label"><code>progress(100cqw, 200px, 480px)</code>: the width of the box, as a ratio.</p> <div class="resizable"> <p class="grow">Resize me</p> <div class="line"></div> </div></div>
web-features The sibling-count() and sibling-index() CSS functions return integers that are useful to style elements based on their positions among siblings or on the number of siblings, for example as part of a calc() expression.
sibling-count() and sibling-index()Written for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-sib"> <p class="unsupported">This browser does not support sibling-index() and sibling-count(), so the cards stay flat.</p> <p class="hint">Add or remove cards. No custom property is set: every card reads its own position.</p> <div class="controls"> <button type="button" id="add">Add card</button> <button type="button" id="remove">Remove card</button> <output id="total">5 cards</output> </div> <ol class="fan" id="fan"> <li></li> <li></li> <li></li> <li></li> <li></li> </ol></div>
<div class="demo-fs"> <p class="unsupported" role="note">field-sizing is not supported in this browser, so the fields keep their fixed size.</p> <fieldset class="mode"> <legend>field-sizing</legend> <label><input type="radio" name="mode" id="mode-content" checked> content</label> <label><input type="radio" name="mode" id="mode-fixed"> fixed</label> </fieldset> <p class="hint">Type in the fields. They grow with the text, no script.</p> <p class="sentence"> <label>Hi, my name is <input type="text" class="inline" placeholder="your name"></label> </p> <p class="sentence"> <label>and I am learning <input type="text" class="inline" placeholder="a topic"></label> </p> <div class="chat"> <label for="message">Message</label> <textarea id="message" rows="2">Hello!</textarea> </div></div>
Browser support
First browser version supporting the whole field-sizing feature
Chrome
123
Edge
123
Firefox
152
Safari
26.2
Chrome Android
123
Safari iOS
26.2
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
<div class="demo-csq"> <p class="unsupported">Container style queries are not supported in this browser, so the cards stay in the light theme.</p> <div class="stage"> <fieldset class="controls"> <legend>Set --theme on the container</legend> <label><input type="radio" name="theme" id="t-light" checked> light</label> <label><input type="radio" name="theme" id="t-dark"> dark</label> <label><input type="radio" name="theme" id="t-sunset"> sunset</label> <label><input type="radio" name="theme" id="t-ocean"> ocean</label> <label class="check"><input type="checkbox" id="compact"> --compact: true</label> </fieldset> <div class="scene"> <article class="profile"> <div class="avatar" aria-hidden="true">MO</div> <div class="info"> <h2>Maya Okafor</h2> <p class="role">Design engineer</p> <p class="bio">Builds interfaces that adapt to their surroundings, with no extra classes.</p> <button type="button">Follow</button> </div> </article> <div class="pin"> <article class="profile"> <div class="avatar" aria-hidden="true">LP</div> <div class="info"> <h2>Leo Park</h2> <p class="role">Pinned to sunset</p> <p class="bio">This card sits in a wrapper that sets its own theme, so the switch above does not reach it.</p> <button type="button">Follow</button> </div> </article> </div> </div> </div></div>
Browser support
First browser version supporting the whole Container style queries feature
Chrome
111
Edge
111
Firefox
151
Safari
18
Chrome Android
111
Safari iOS
18
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
<div class="demo-open"> <p class="unsupported" role="status">This browser does not support :open, so the cards below never show the open state.</p> <p class="hint">Open each control. Its card lights up and the badge follows the state.</p> <div class="grid"> <section class="card" aria-labelledby="c1"> <h2 id="c1">details</h2> <details> <summary>Shipping times</summary> <p>Orders leave the warehouse within two working days.</p> </details> </section> <section class="card" aria-labelledby="c2"> <h2 id="c2">select</h2> <label for="fruit" class="sr">Fruit</label> <select id="fruit"> <option>Apple</option> <option>Banana</option> <option>Cranberry</option> <option>Fig</option> </select> </section> <section class="card" aria-labelledby="c3"> <h2 id="c3">input</h2> <label for="day" class="sr">Day</label> <input id="day" type="date" value="2026-11-05"> </section> <section class="card" aria-labelledby="c4"> <h2 id="c4">dialog</h2> <button type="button" id="toggle">Toggle the dialog</button> <dialog id="note"> <p>Hello from a dialog.</p> <form method="dialog"><button>Close</button></form> </dialog> </section> </div></div>
web-features The text-decoration-skip-ink: all CSS declaration forces interruptions in underlines and overlines where the line would cross a glyph. This contrasts with auto, which does not skip for CJK glyphs.
Live previewExample from MDN
p { font: 1.9em "Georgia", serif; text-decoration: underline;}
<div class="demo-hl"> <p class="unsupported">Custom highlights are not supported in this browser. Searching will not mark the text.</p> <div class="search" role="search"> <label for="q">Find in the text</label> <input id="q" type="search" value="text" autocomplete="off" spellcheck="false"> <button id="prev" type="button">Previous</button> <button id="next" type="button">Next</button> <output id="count" aria-live="polite"></output> </div> <article id="doc"> <p>A custom highlight paints a range of text without touching the markup. The text stays a plain text node, so nothing is wrapped and nothing reflows.</p> <p>Type a word above. Each match becomes a range, and every range joins one named highlight. The browser draws the highlight, and the page styles it with a single rule.</p> <p>Use the buttons to move between matches. The current match belongs to a second highlight with a higher priority, so its color wins over the others.</p> </article> <p class="dom">Elements added to the article to draw the marks: <output id="added">0</output></p></div>
const doc = document.getElementById("doc");const input = document.getElementById("q");const count = document.getElementById("count");const added = document.getElementById("added");if (CSS.highlights) { const search = new Highlight(); const current = new Highlight(); current.priority = 1; // wins over "search" where both paint the same text CSS.highlights.set("search", search); CSS.highlights.set("current", current); const elementsBefore = doc.getElementsByTagName("*").length; let ranges = []; let index = 0; function find() { ranges = []; const term = input.value.trim().toLowerCase(); if (term) { const walker = document.createTreeWalker(doc, NodeFilter.SHOW_TEXT); for (let node = walker.nextNode(); node; node = walker.nextNode()) { const text = node.data.toLowerCase(); for (let at = text.indexOf(term); at !== -1; at = text.indexOf(term, at + term.length)) { const range = new Range(); range.setStart(node, at); range.setEnd(node, at + term.length); ranges.push(range); } } } index = 0; paint(); } function paint() { search.clear(); current.clear(); ranges.forEach((range) => search.add(range)); if (ranges.length) current.add(ranges[index]); count.value = ranges.length ? `${index + 1} of ${ranges.length}` : "No match"; added.value = doc.getElementsByTagName("*").length - elementsBefore; } function step(by) { if (!ranges.length) return; index = (index + by + ranges.length) % ranges.length; paint(); } input.addEventListener("input", find); input.addEventListener("keydown", (event) => { if (event.key === "Enter") step(event.shiftKey ? -1 : 1); }); document.getElementById("next").addEventListener("click", () => step(1)); document.getElementById("prev").addEventListener("click", () => step(-1)); find();}
Browser support
First browser version supporting the whole Custom highlights feature
Chrome
105
Edge
105
Firefox
149
Safari
17.2
Chrome Android
105
Safari iOS
17.2
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
<section id="default-example"> <div id="example-element"> <p> This text is contained within a single paragraph. This paragraph is two sentences long. </p> <p> This is a new paragraph. There is a line break element <code><br></code> after this sentence.<br />There it is! Notice how it affects the indentation. </p> </div></section>
<div class="demo-hang"> <p class="unsupported" role="status">This browser does not support <code>text-indent: hanging</code>. The entries below are not indented.</p> <div class="controls"> <fieldset> <legend>text-indent</legend> <label><input type="radio" name="mode" id="m-none"> 0</label> <label><input type="radio" name="mode" id="m-first"> first line</label> <label><input type="radio" name="mode" id="m-hang" checked> hanging</label> </fieldset> <label class="size" for="indent">Indent</label> <input type="range" id="indent" min="0" max="6" step="0.5" value="2.5"> <output id="indent-out" for="indent">2.5em</output> </div> <section class="refs"> <h2>References</h2> <p class="entry">Okafor, N., & Lindqvist, A. (2021). The long tail of typography: how readers scan a page of citations. <i>Journal of Applied Letterforms, 14</i>(2), 101–128.</p> <p class="entry">Marchetti, G. (2019). A short history of the hanging paragraph in printed bibliographies. Meridian University Press.</p> <p class="entry">Tanaka, K., Brun, E., & Adeyemi, O. (2023). Alignment and recall in reference lists. <i>Proceedings of the Symposium on Reading Behaviour</i>, 55–63.</p> <p class="entry">Voss, H. (2018). Margins. Lantern Books.</p> </section></div>
Newly available since February 2026Clipping, shapes, and masking
web-features The shape() CSS function creates shapes with a series of commands like line, move, and curve. It can be used with clip-path and shape-outside.
shape()Written for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
.demo-shape { max-width: 860px; margin-inline: auto; color: #1e1b4b; }.demo-shape .hint { margin: 0 0 14px; color: #4b5563; }.demo-shape .unsupported { display: none; margin: 0 0 12px; padding: 8px 12px; border: 1px solid #f59e0b; border-radius: 8px; background: #fef3c7; color: #78350f;}@supports not (clip-path: shape(from 0 0, line to 10px 10px)) { .demo-shape .unsupported { display: block; }}.demo-shape .row { display: flex; flex-wrap: wrap; gap: 28px; align-items: flex-start; }/* The drop shadow lives on the parent: it follows the clipped shape, and it doubles as the focus ring because an outline would be clipped away. */.demo-shape .blob-wrap { width: 240px; max-width: 100%; filter: drop-shadow(0 10px 12px rgb(67 56 202 / 0.35));}.demo-shape .blob-wrap:has(.blob:focus-visible) { filter: drop-shadow(0 0 3px #1d4ed8) drop-shadow(0 0 3px #1d4ed8);}/* Both shapes use the same commands in the same order, so they interpolate. */.demo-shape .blob { display: block; width: 100%; aspect-ratio: 1; border: 0; font: 700 1.2rem system-ui, sans-serif; color: #fff; background: linear-gradient(135deg, #4f46e5, #db2777); cursor: pointer; clip-path: shape( from 45% 0%, curve to 100% 40% with 80% 0% / 100% 15%, curve to 60% 100% with 100% 75% / 85% 100%, curve to 0% 55% with 30% 100% / 0% 85%, curve to 45% 0% with 0% 20% / 15% 0%, close ); transition: clip-path 0.7s ease;}.demo-shape .blob:is(:hover, :focus-visible) { clip-path: shape( from 60% 5%, curve to 95% 60% with 90% 0% / 100% 35%, curve to 40% 95% with 90% 90% / 65% 100%, curve to 5% 40% with 15% 100% / 0% 65%, curve to 60% 5% with 10% 15% / 30% 0%, close );}.demo-shape .wave-box { flex: 1 1 240px; min-width: 200px; max-width: 100%; overflow: auto; resize: horizontal;}/* Percentages and pixels mix: the edge stretches, the dip stays 40px. */.demo-shape .wave { padding: 22px 22px 70px; color: #fff; background: linear-gradient(160deg, #0f766e, #2563eb); clip-path: shape( from 0 0, hline to 100%, vline to calc(100% - 40px), curve to 50% calc(100% - 40px) with 75% 100%, smooth to 0 calc(100% - 40px), close );}.demo-shape .wave h2 { margin: 0 0 6px; font-size: 1.3rem; }.demo-shape .wave p { margin: 0; }@media (prefers-reduced-motion: reduce) { .demo-shape .blob { transition: none; }}
<div class="demo-shape"> <p class="unsupported">shape() is not supported in this browser. The blob and the wave fall back to plain boxes.</p> <p class="hint">Hover or focus the blob. Drag the corner handle of the wave card.</p> <div class="row"> <div class="blob-wrap"> <button class="blob" type="button">Morph me</button> </div> <div class="wave-box"> <div class="wave"> <h2>Wave edge</h2> <p>The dip is always 40px tall, at any width.</p> </div> </div> </div></div>
Browser support
First browser version supporting the whole shape() feature
Chrome
135
Edge
135
Firefox
148
Safari
18.4
Chrome Android
135
Safari iOS
18.4
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
Newly available since January 2026View transitions
web-features The :active-view-transition CSS pseudo-class matches the root element when a view transition is active. The :active-view-transition-type() CSS pseudo-class matches only when the active view transition was started with the specified type.
web-features The rcap CSS length unit is a font-relative length equal to the value of the cap unit on the root element. Cap-height is approximately equal to the height of a capital Latin letter.
web-features The rch CSS length unit is a font-relative length equal to the value of the ch unit on the root element. ch length is based on the width of the zero (0) character.
web-features The ric CSS length unit, or root international character, is a font-relative length equal to the width of CJK character relative to the root element.
<div class="sc"> <p class="unsupported" role="note">Your browser does not support scrollbar-color. The scrollbars below use the default look.</p> <h1 class="sc-title">Same content, three scrollbars</h1> <p class="sc-hint">Scroll each box. Hover a box to swap its colors.</p> <div class="sc-grid"> <div class="sc-box sc-grape" tabindex="0" role="region" aria-label="Grape scrollbar"> <h2>Grape</h2> <p>The thumb is the part you drag.</p> <p>The track is the lane it moves in.</p> <p>One declaration sets both colors.</p> <p>The first color is the thumb.</p> <p>The second color is the track.</p> <p>No pseudo-elements are needed.</p> <p>The colors can even transition.</p> </div> <div class="sc-box sc-mint" tabindex="0" role="region" aria-label="Mint scrollbar"> <h2>Mint</h2> <p>The thumb is the part you drag.</p> <p>The track is the lane it moves in.</p> <p>One declaration sets both colors.</p> <p>The first color is the thumb.</p> <p>The second color is the track.</p> <p>No pseudo-elements are needed.</p> <p>The colors can even transition.</p> </div> <div class="sc-box sc-night" tabindex="0" role="region" aria-label="Night scrollbar"> <h2>Night</h2> <p>The thumb is the part you drag.</p> <p>The track is the lane it moves in.</p> <p>One declaration sets both colors.</p> <p>The first color is the thumb.</p> <p>The second color is the track.</p> <p>No pseudo-elements are needed.</p> <p>The colors can even transition.</p> </div> </div></div>
Browser support
First browser version supporting the whole scrollbar-color feature
Chrome
121
Edge
121
Firefox
64
Safari
26.2
Chrome Android
121
Safari iOS
26.2
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The text-decoration-line: spelling-error and text-decoration-line: grammar-error CSS declarations apply the browser's marking for spelling and grammatical mistakes. This is typically a wavy underline in red or green.
Live previewExample from MDN
p { font: 1.5em sans-serif;}
<section id="default-example"> <p> I'd far rather be <span class="transition-all" id="example-element">happy than right</span> any day. </p></section>
.demo-vt, .demo-vt * { box-sizing: border-box; }.demo-vt { max-width: 860px; margin: 0 auto; }.demo-vt .hint { margin: 0 0 12px; }.demo-vt .unsupported { display: none; margin: 0 0 12px; padding: 10px 12px; border: 2px dashed #b45309; border-radius: 8px; background: #fffbeb; }@supports not (view-transition-name: a) { .demo-vt .unsupported { display: block; }}.demo-vt .controls { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 14px; }.demo-vt .controls button { font: inherit; font-weight: 600; padding: 8px 16px; border: 2px solid #1b1b1b; border-radius: 8px; background: #fff; color: #1b1b1b; cursor: pointer; }.demo-vt .controls button:hover { background: #eef2ff; }.demo-vt button:focus-visible { outline: 3px solid #1d4ed8; outline-offset: 2px; }.demo-vt .cards { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 12px; }.demo-vt .cards.list { grid-template-columns: 1fr; }.demo-vt .cards li { height: 84px; border-radius: 14px; overflow: hidden; }.demo-vt .cards.list li { height: 52px; }.demo-vt .cards li button { display: block; width: 100%; height: 100%; border: 0; color: #fff; font: inherit; font-size: 1.1rem; font-weight: 700; cursor: pointer; background: inherit; text-align: center; }.demo-vt .cards.list li button { text-align: left; padding-inline: 20px; }.demo-vt #card-a { background: #b45309; view-transition-name: card-a; }.demo-vt #card-b { background: #be185d; view-transition-name: card-b; }.demo-vt #card-c { background: #1d4ed8; view-transition-name: card-c; }.demo-vt #card-d { background: #0e7490; view-transition-name: card-d; }.demo-vt #card-e { background: #b91c1c; view-transition-name: card-e; }.demo-vt #card-f { background: #15803d; view-transition-name: card-f; }/* The page itself does not animate: only the named cards fly to their new place. */::view-transition-old(root),::view-transition-new(root) { animation: none; }/* Every card gets its own group. It moves and resizes from the old box to the new one. */::view-transition-group(*) { animation-duration: 0.55s; animation-timing-function: cubic-bezier(0.3, 1.2, 0.5, 1); }/* The image pair holds the old and the new snapshot of a card, cross-faded while it moves. */::view-transition-image-pair(*) { isolation: isolate; }::view-transition-old(*) { animation-duration: 0.25s; }::view-transition-new(*) { animation-duration: 0.55s; }@media (prefers-reduced-motion: reduce) { ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation-duration: 0.01s; }}
<div class="demo-vt"> <p class="unsupported">This browser does not support view transitions, so the cards change place without animation.</p> <p class="hint">Click a card to send it to the front, or shuffle them all.</p> <div class="controls"> <button type="button" id="shuffle">Shuffle</button> <button type="button" id="layout" aria-pressed="false">List layout</button> </div> <ul class="cards" id="cards"> <li id="card-a"><button type="button">Amber</button></li> <li id="card-b"><button type="button">Berry</button></li> <li id="card-c"><button type="button">Cobalt</button></li> <li id="card-d"><button type="button">Denim</button></li> <li id="card-e"><button type="button">Ember</button></li> <li id="card-f"><button type="button">Forest</button></li> </ul></div>
const cards = document.getElementById("cards");const layout = document.getElementById("layout");// Run the DOM change inside a view transition when the browser has them.const change = (update) => { if (document.startViewTransition) document.startViewTransition(update); else update();};document.getElementById("shuffle").addEventListener("click", () => { change(() => { const items = [...cards.children]; for (let i = items.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [items[i], items[j]] = [items[j], items[i]]; } cards.append(...items); });});layout.addEventListener("click", () => { change(() => { const list = cards.classList.toggle("list"); layout.setAttribute("aria-pressed", String(list)); layout.textContent = list ? "Grid layout" : "List layout"; });});cards.addEventListener("click", (event) => { const card = event.target.closest("li"); if (card && card !== cards.firstElementChild) change(() => cards.prepend(card));});
Browser support
First browser version supporting the whole View transitions feature
Chrome
111
Edge
111
Firefox
144
Safari
18
Chrome Android
111
Safari iOS
18
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
Newly available since October 2025View transitions
web-features The view-transition-class CSS property sets a name that can be used to apply styles to multiple named view transition pseudo-elements.
Live previewExample from MDN
/* Each element must have a unique view-transition-name */#card1 { view-transition-name: card-1;}#card2 { view-transition-name: card-2;}#card3 { view-transition-name: card-3;}/* But they can all share the same view-transition-class */.card { view-transition-class: card;}/* This single rule applies to all three cards' transitions */::view-transition-group(.card) { animation-duration: 0.5s; animation-timing-function: ease-in-out;}
<div class="demo-details"> <p class="unsupported" role="note">::details-content is not supported in this browser, so the panels open without animation.</p> <p class="hint">Click a question. Only one panel stays open.</p> <details name="faq" open> <summary>What is animated here?</summary> <p>Only the panel body. The summary stays put while its content grows from zero height.</p> </details> <details name="faq"> <summary>Why does one panel close the other?</summary> <p>The three panels share the same name attribute, so opening one closes the others.</p> </details> <details name="faq"> <summary>Do I need JavaScript?</summary> <p>No. The panel opens and closes with the plain details element, and the animation is one CSS transition on its content.</p> </details></div>
Browser support
First browser version supporting the whole ::details-content feature
Chrome
131
Edge
131
Firefox
143
Safari
18.4
Chrome Android
131
Safari iOS
18.4
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
<div class="cv"> <p class="unsupported" role="note">Your browser does not support content-visibility. All the cards are always rendered.</p> <h1 class="cv-title">A list of 600 cards</h1> <div class="cv-bar"> <label class="cv-toggle"><input type="checkbox" id="cv-toggle" checked> <code>content-visibility: auto</code></label> <p class="cv-status">Rendered: <strong id="cv-count">0</strong> of <span id="cv-total">0</span>. Layout of all cards: <strong id="cv-time" aria-live="polite">0 ms</strong>.</p> </div> <div class="cv-scroller" tabindex="0" role="region" aria-label="Scrollable list of cards"> <ol class="cv-list" id="cv-list"></ol> </div></div>
// The cards are built here so the demo stays short; the CSS is what matters.const list = document.getElementById("cv-list");const scroller = list.parentElement;const toggle = document.getElementById("cv-toggle");const count = document.getElementById("cv-count");const time = document.getElementById("cv-time");const total = 600;document.getElementById("cv-total").textContent = total;// The browser tells us each time it starts or stops skipping the contents of a card.const rendered = new Set();function showCount() { count.textContent = toggle.checked ? rendered.size : total;}list.addEventListener("contentvisibilityautostatechange", (event) => { if (event.skipped) rendered.delete(event.target); else rendered.add(event.target); showCount();});// Build the list again under the chosen value and time the layout of all the cards.function build() { const cards = document.createDocumentFragment(); for (let i = 1; i <= total; i++) { const card = document.createElement("li"); card.className = "cv-card"; card.innerHTML = '<span class="cv-n">' + i + "</span><div><h2>Card " + i + "</h2><p>Many small boxes to lay out and paint.</p></div>" + '<div class="cv-tiles">' + "<i></i>".repeat(30) + "</div>"; cards.append(card); } rendered.clear(); list.replaceChildren(); scroller.scrollTop = 0; const start = performance.now(); list.append(cards); list.getBoundingClientRect(); // forces the layout the browser would otherwise delay time.textContent = Math.round(performance.now() - start) + " ms"; showCount();}toggle.addEventListener("change", build);build();
Browser support
First browser version supporting the whole content-visibility feature
Chrome
108
Edge
108
Firefox
130
Safari
26
Chrome Android
108
Safari iOS
26
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
.demo-as, .demo-as * { box-sizing: border-box; }.demo-as { --v: 60; max-width: 860px; margin: 0 auto; }.demo-as .hint { margin: 0 0 12px; }.demo-as .unsupported { display: none; margin: 0 0 12px; padding: 10px 12px; border: 2px dashed #b45309; border-radius: 8px; background: #fffbeb; }@supports not (width: abs(-1px)) { .demo-as .unsupported { display: block; }}.demo-as .controls { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; font-weight: 600; }.demo-as .controls input { flex: 1; max-width: 420px; accent-color: #1d4ed8; }.demo-as .controls input:focus-visible { outline: 3px solid #1d4ed8; outline-offset: 3px; }.demo-as output { min-width: 4ch; font-variant-numeric: tabular-nums; }.demo-as .board { padding: 18px; border-radius: 12px; background: #f1f5f9; }/* sign() is -1, 0 or 1: as a scale it flips the arrow, and at 0 it makes it vanish. */.demo-as .arrow { width: 120px; height: 56px; margin: 0 auto 18px; clip-path: polygon(0 28%, 58% 28%, 58% 0, 100% 50%, 58% 100%, 58% 72%, 0 72%); scale: sign(var(--v)) 1; /* The hue also follows the sign: orange left, green right. */ background: hsl(calc(92 + sign(var(--v)) * 68) 70% 38%);}/* The bar starts at the middle. abs() is its length, sign() decides which side it grows to. */.demo-as .track { position: relative; height: 30px; border-radius: 15px; background: #e2e8f0; overflow: hidden; }.demo-as .track::after { content: ""; position: absolute; left: 50%; top: 0; width: 2px; height: 100%; background: #1b1b1b; }.demo-as .bar { position: absolute; top: 0; left: 50%; height: 100%; width: calc(abs(var(--v)) * 0.5%); translate: calc(min(sign(var(--v)), 0) * 100%) 0; background: hsl(calc(92 + sign(var(--v)) * 68) 70% 38%);}.demo-as .read { margin: 14px 0 0; text-align: center; }@media (prefers-reduced-motion: no-preference) { .demo-as .arrow { transition: scale 0.25s; }}
<div class="demo-as"> <p class="unsupported">This browser does not support abs() and sign(), so the arrow and the bar do not react.</p> <p class="hint">Drag the velocity left and right, and stop at zero. One number drives everything.</p> <div class="controls"> <label for="v">Velocity</label> <input type="range" id="v" min="-100" max="100" value="60"> <output id="out" for="v" aria-live="polite">60</output> </div> <div class="board"> <div class="arrow" aria-hidden="true"></div> <div class="track" aria-hidden="true"><div class="bar"></div></div> <p class="read"><code>sign()</code> is <b id="sign">1</b>, <code>abs()</code> is <b id="abs">60</b></p> </div></div>
const demo = document.querySelector(".demo-as");const slider = document.getElementById("v");// The CSS does the work. This only prints the two numbers it receives.slider.addEventListener("input", () => { const v = Number(slider.value); demo.style.setProperty("--v", v); document.getElementById("out").textContent = v; document.getElementById("sign").textContent = Math.sign(v); document.getElementById("abs").textContent = Math.abs(v);});
Browser support
First browser version supporting the whole abs() and sign() feature
Chrome
138
Edge
138
Firefox
118
Safari
15.4
Chrome Android
138
Safari iOS
15.4
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The print-color-adjust CSS property sets whether styles of printed pages should be adjusted to use less ink, in cases such as light text on a dark background.
print-color-adjustWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-pca"> <p class="unsupported">Your browser does not support print-color-adjust, so it may drop backgrounds when printing.</p> <label class="sim"><input type="checkbox" id="sim"> Simulate a print without background graphics</label> <div class="panels"> <section class="panel economy"> <h2>economy</h2> <ul class="bars" aria-label="Sales by quarter"> <li style="--w: 85%">Q1</li> <li style="--w: 60%">Q2</li> <li style="--w: 95%">Q3</li> </ul> <ul class="stripes" aria-label="Rows"> <li>Row one</li> <li>Row two</li> <li>Row three</li> </ul> </section> <section class="panel exact"> <h2>exact</h2> <ul class="bars" aria-label="Sales by quarter"> <li style="--w: 85%">Q1</li> <li style="--w: 60%">Q2</li> <li style="--w: 95%">Q3</li> </ul> <ul class="stripes" aria-label="Rows"> <li>Row one</li> <li>Row two</li> <li>Row three</li> </ul> </section> </div> <p class="note">Both panels look the same on screen. Press Ctrl+P (or Cmd+P) in the page and keep "Background graphics" off: browsers may then drop the left panel's backgrounds, leaving its pale title and bars hard to read. The right panel asks to keep them.</p></div>
Browser support
First browser version supporting the whole print-color-adjust feature
Chrome
136
Edge
136
Firefox
97
Safari
15.4
Chrome Android
136
Safari iOS
15.4
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The popover HTML attribute creates an overlay to display content on top of other page content. Popovers can be shown declaratively using HTML, or using the showPopover() method.
PopoverWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-target"> <p class="unsupported" role="status">This browser does not support <code>::target-text</code>. Text fragment links still scroll, without the highlight.</p> <div class="controls"> <fieldset> <legend>Text fragment</legend> <label><input type="radio" name="frag" id="frag-1" checked> slow tide</label> <label><input type="radio" name="frag" id="frag-2"> copper lanterns</label> <label><input type="radio" name="frag" id="frag-3"> last ferry</label> </fieldset> <fieldset> <legend>::target-text style</legend> <label><input type="radio" name="hl" id="hl-marker" checked> Marker</label> <label><input type="radio" name="hl" id="hl-ink"> Ink</label> <label><input type="radio" name="hl" id="hl-wave"> Wavy</label> </fieldset> </div> <p class="address" aria-live="polite"><span class="bar"></span></p> <article class="page"> <h2>Harbour notes</h2> <p>The morning starts with the <mark class="hit m1">slow tide</mark> pulling nets across the quay, and the gulls argue over the first fish of the day.</p> <p>By noon the market fills with voices. Children chase each other between stalls, and an old woman sells oranges from a basket older than the harbour wall.</p> <p>At dusk the <mark class="hit m2">copper lanterns</mark> are lit one by one along the pier. Their light spills on the water and the bay turns the colour of tea.</p> <p>Nobody hurries after dark. The <mark class="hit m3">last ferry</mark> leaves at ten, and the lamplighter walks home whistling the same song.</p> </article> <p class="note">A sandboxed frame cannot follow a <code>#:~:text=</code> link, so the marks above are painted by hand with the same colours. In your own page, the browser applies <code>::target-text</code> itself.</p></div>
Browser support
First browser version supporting the whole ::target-text feature
Chrome
89
Edge
89
Firefox
131
Safari
18.2
Chrome Android
89
Safari iOS
18.2
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The ruby-position CSS property sets the position of a ruby annotation in relation to its base text. Annotations can display over, under, or interleaved with the base text.
web-features The scrollbar-gutter CSS property reserves space for the scrollbar, preventing unwanted layout changes as the scrollbar appears and disappears.
scrollbar-gutterWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="sg"> <p class="unsupported" role="note">Your browser does not support scrollbar-gutter. The boxes below behave like the first one.</p> <h1 class="sg-title">Does the content jump?</h1> <label class="sg-toggle"><input type="checkbox"> Add more text</label> <p class="sg-hint">Watch the blue bar. Systems with overlay scrollbars show no difference.</p> <div class="sg-grid"> <div class="sg-box sg-auto" tabindex="0" role="region" aria-label="scrollbar-gutter auto"> <h2><code>auto</code></h2> <div class="sg-ruler">Full width</div> <p class="sg-more">More text pushes the box past its height.</p> <p class="sg-more">The scrollbar appears and takes space.</p> <p class="sg-more">The blue bar gets narrower.</p> </div> <div class="sg-box sg-stable" tabindex="0" role="region" aria-label="scrollbar-gutter stable"> <h2><code>stable</code></h2> <div class="sg-ruler">Full width</div> <p class="sg-more">More text pushes the box past its height.</p> <p class="sg-more">The scrollbar appears and takes space.</p> <p class="sg-more">The blue bar keeps its width.</p> </div> <div class="sg-box sg-both" tabindex="0" role="region" aria-label="scrollbar-gutter stable both-edges"> <h2><code>stable both-edges</code></h2> <div class="sg-ruler">Full width</div> <p class="sg-more">More text pushes the box past its height.</p> <p class="sg-more">The scrollbar appears and takes space.</p> <p class="sg-more">Both sides stay symmetric.</p> </div> </div></div>
Browser support
First browser version supporting the whole scrollbar-gutter feature
Chrome
94
Edge
94
Firefox
97
Safari
18.2
Chrome Android
94
Safari iOS
18.2
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The text-wrap CSS property sets how lines break in text that overflows the container. It is a shorthand for text-wrap-style and text-wrap-mode.
text-wrapWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-wrap"> <p class="unsupported" role="status">This browser does not support <code>text-wrap: balance</code>. The headings below wrap the default way.</p> <p class="hint">Drag the bottom-right corner of the box to resize it.</p> <div class="stage"> <section class="sample"> <h2>Default</h2> <p class="title title-wrap">Balanced headings spread their words evenly across every line</p> </section> <section class="sample"> <h2>Balanced</h2> <p class="title title-balance">Balanced headings spread their words evenly across every line</p> </section> <section class="sample"> <h2>No wrap</h2> <p class="title title-nowrap">Balanced headings spread their words evenly across every line</p> </section> </div></div>
Browser support
First browser version supporting the whole text-wrap feature
Chrome
130
Edge
130
Firefox
124
Safari
17.5
Chrome Android
130
Safari iOS
17.5
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The from keyword for color functions (color(), hsl(), oklch(), etc.) creates a new color based on a given color by modifying the values of the input color. Also known as relative color syntax (RCS).
Relative colorsWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
web-features The @starting-style CSS at-rule sets the starting values for properties that are transitioning when the target element's style is first updated.
@starting-styleWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-start"> <p class="unsupported">This browser does not support @starting-style. Cards and the dialog appear without a transition.</p> <div class="bar"> <button type="button" id="add-card">Add a card</button> <button type="button" id="clear-cards" class="ghost">Clear</button> <button type="button" id="open-dialog" class="ghost">Open the dialog</button> </div> <ul class="cards" id="cards"></ul> <dialog id="dialog" aria-labelledby="dialog-title"> <h2 id="dialog-title">Starting from nothing</h2> <p>This dialog was hidden a moment ago. It grows from its starting style.</p> <form method="dialog"> <button type="submit" id="close-dialog">Close</button> </form> </dialog></div>
Newly available since August 2024Transitions (CSS)
web-features The transition-behavior: allow-discrete CSS declaration allows transitions for properties whose animation behavior is discrete. Such properties can't be interpolated and swap from their start value to the end value at 50%.
transition-behaviorWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-behavior"> <p class="unsupported">This browser does not support transition-behavior: allow-discrete. Both cards disappear at once.</p> <label class="switch"> <input type="checkbox" id="hide-cards"> <span>Hide both cards</span> </label> <div class="pair"> <div class="slot"> <div class="card normal"> <strong>normal</strong> <span>display flips at the first frame, nothing is left to fade.</span> </div> </div> <div class="slot"> <div class="card smart"> <strong>allow-discrete</strong> <span>display waits for the end of the fade.</span> </div> </div> </div></div>
Browser support
First browser version supporting the whole transition-behavior feature
Chrome
117
Edge
117
Firefox
129
Safari
17.4
Chrome Android
117
Safari iOS
17.4
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The font-size-adjust CSS property preserves apparent text size, regardless of the font used, by scaling fonts to the same size with respect to a specific metric, such as x-height. This can help make fallback fonts look the same size.
font-size-adjustWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-fsa"> <p class="unsupported" role="status">This browser does not support <code>font-size-adjust</code>. Both lines keep the same font size, so the serif looks smaller.</p> <fieldset class="modes"> <legend>font-size-adjust</legend> <label><input type="radio" name="mode" id="m-none" checked> none</label> <label><input type="radio" name="mode" id="m-ex"> ex-height 0.545</label> <label><input type="radio" name="mode" id="m-cap"> cap-height 0.73</label> </fieldset> <p class="hint">Both lines are 40px. The coloured bar is the height of the letter x (or of a capital H) in that font.</p> <div class="stage"> <div class="row sans"> <p class="label">Sans, Verdana-like</p> <p class="line"><span class="bar" aria-hidden="true"></span>Hex wax box</p> </div> <div class="row serif"> <p class="label">Serif, Times-like</p> <p class="line"><span class="bar" aria-hidden="true"></span>Hex wax box</p> </div> </div></div>
Browser support
First browser version supporting the whole font-size-adjust feature
Chrome
127
Edge
127
Firefox
118
Safari
17
Chrome Android
127
Safari iOS
17
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The / notation in content CSS property values adds alternative text to generated content. For example, the content: url('upvote-icon.svg') / 'Upvote' declaration adds accessible 'Upvote' text to the SVG icon. Also known as alternate text.
<p class="topic-games">Game News: A new inFamous is not planned</p><p class="topic-weather"> Weather for Today: Heat, violent storms and twisters</p><p class="topic-hot">Trending Article: Must-watch videos of the week</p>
web-features The CSS.registerProperty() static method and the @property CSS at-rule register custom properties for which types and behaviors can be defined.
Registered custom propertiesWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
/* @property gives a custom property a type, so the browser can interpolate it. */@property --angle { syntax: "<angle>"; inherits: false; initial-value: 0deg;}@property --count { syntax: "<integer>"; inherits: false; initial-value: 0;}/* Support probe: --supported is never set, so it only reads 1 where @property registered its initial value. at-rule(@property) is not an option: browsers without at-rule() would drop the whole @supports block. */@property --supported { syntax: "<integer>"; inherits: true; initial-value: 1;}.demo-prop, .demo-prop * { box-sizing: border-box; }.demo-prop { max-width: 860px; margin: 0 auto; --off: calc(1 - var(--supported, 0)); }.demo-prop .hint { margin: 0 0 14px; }.demo-prop .unsupported { overflow: hidden; max-height: calc(var(--off) * 200px); margin: 0 0 calc(var(--off) * 14px); padding: calc(var(--off) * 10px) 12px; border: solid #b45309; border-width: calc(var(--off) * 2px); border-radius: 8px; background: #fffbeb;}.demo-prop .pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 16px; }.demo-prop .ring { display: grid; padding: 5px; border-radius: 24px; animation: ring-spin 3s linear infinite;}.demo-prop .ring:focus-visible { outline: 3px solid #1b1b1b; outline-offset: 3px; }.demo-prop .inner { display: grid; gap: 6px; justify-items: center; padding: 24px 12px; border-radius: 19px; background: #fff; text-align: center;}.demo-prop .note { font-size: 0.85rem; color: #475569; }.demo-prop .stat { font-size: 2.2rem; font-weight: 700; font-variant-numeric: tabular-nums;}.demo-prop .stat::after { content: counter(shown) "%"; }/* Registered: --angle and --count are typed, so they animate and transition smoothly. */.demo-prop .registered { background: conic-gradient(from var(--angle), #e11d48, #f59e0b, #16a34a, #2563eb, #e11d48); }.demo-prop .registered .stat { counter-reset: shown var(--count); transition: --count 1.4s ease-out; }.demo-prop .registered:hover .stat, .demo-prop .registered:focus-visible .stat { --count: 100; }@keyframes ring-spin { to { --angle: 360deg; } }/* Not registered: --turn and --total are plain text, so the browser can only flip them. */.demo-prop .plain { background: conic-gradient(from var(--turn, 0deg), #e11d48, #f59e0b, #16a34a, #2563eb, #e11d48); animation-name: ring-spin-plain; }.demo-prop .plain .stat { counter-reset: shown var(--total, 0); transition: --total 1.4s ease-out; }.demo-prop .plain:hover .stat, .demo-prop .plain:focus-visible .stat { --total: 100; }@keyframes ring-spin-plain { to { --turn: 360deg; } }@media (prefers-reduced-motion: reduce) { .demo-prop .ring { animation: none; } .demo-prop .stat { transition: none; }}
<div class="demo-prop"> <p class="unsupported">This browser does not support @property, so both cards behave the same.</p> <p class="hint">Hover or focus each card. Only the registered property animates.</p> <div class="pair"> <div class="ring registered" tabindex="0"> <div class="inner"> <strong>Registered</strong> <span class="note">--angle is an <angle></span> <span class="stat"></span> </div> </div> <div class="ring plain" tabindex="0"> <div class="inner"> <strong>Not registered</strong> <span class="note">--turn is plain text</span> <span class="stat"></span> </div> </div> </div></div>
Browser support
First browser version supporting the whole Registered custom properties feature
Chrome
85
Edge
85
Firefox
128
Safari
16.4
Chrome Android
85
Safari iOS
16.4
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features Gradient interpolation controls how the colors between gradient stops are calculated in CSS. For example, linear-gradient(to right in oklch longer hue, red, red); calculates in the oklch color space, with the hue going all the way around the hue circle from red back to red.
Gradient interpolationWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-state"> <p class="unsupported" role="status">This browser does not support :state(), so the custom buttons below never change look.</p> <p class="hint">Click a button, or focus it and press Enter. The script only sets states, the stylesheet draws them.</p> <ul class="tasks"> <li> <task-button>Upload photos</task-button> <p class="readout">states: <code aria-live="polite">none</code></p> </li> <li> <task-button>Sync contacts</task-button> <p class="readout">states: <code aria-live="polite">none</code></p> </li> <li> <task-button data-fails>Send newsletter</task-button> <p class="readout">states: <code aria-live="polite">none</code></p> </li> </ul></div>
const STATES = ["busy", "done", "failed"];class TaskButton extends HTMLElement { #internals = this.attachInternals(); #readout; connectedCallback() { this.tabIndex = 0; this.setAttribute("role", "button"); this.#readout = this.parentElement.querySelector("code"); this.addEventListener("click", () => this.#press()); this.addEventListener("keydown", (event) => { if (event.key === "Enter" || event.key === " ") { event.preventDefault(); this.#press(); } }); } // The element holds one state at a time and exposes it to CSS as :state(...). #setState(name) { const states = this.#internals.states; try { for (const state of STATES) states.delete(state); if (name) states.add(name); } catch { return; // an older browser that only knows the dashed-ident syntax } this.#readout.textContent = [...states].join(", ") || "none"; this.setAttribute("aria-busy", String(name === "busy")); } #press() { const states = this.#internals.states; if (states.has("busy")) return; if (states.has("done") || states.has("failed")) return this.#setState(null); this.#setState("busy"); setTimeout(() => this.#setState(this.hasAttribute("data-fails") ? "failed" : "done"), 1400); }}customElements.define("task-button", TaskButton);
Browser support
First browser version supporting the whole :state() feature
Chrome
125
Edge
125
Firefox
126
Safari
17.4
Chrome Android
125
Safari iOS
17.4
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
<div class="demo-zoom"> <div class="control"> <label for="level">Zoom the middle box</label> <input type="range" id="level" min="0.5" max="2" step="0.1" value="1"> <output for="level" id="value">1.0</output> </div> <section class="row" aria-labelledby="h-zoom"> <h2 id="h-zoom"><code>zoom</code>: the neighbours move over</h2> <div class="lane zoomed"> <div class="tile">A</div> <div class="tile target">Zoom</div> <div class="tile">C</div> </div> </section> <section class="row" aria-labelledby="h-scale"> <h2 id="h-scale"><code>transform: scale()</code>: the neighbours stay put</h2> <div class="lane scaled"> <div class="tile">A</div> <div class="tile target">Scale</div> <div class="tile">C</div> </div> </section> <p class="unsupported">zoom is not supported in this browser, so the first row does not change size.</p></div>
var level = document.getElementById("level");var value = document.getElementById("value");level.addEventListener("input", function () { document.querySelector(".demo-zoom").style.setProperty("--z", level.value); value.textContent = Number(level.value).toFixed(1);});
Browser support
First browser version supporting the whole zoom feature
Chrome
1
Edge
12
Firefox
126
Safari
3.1
Chrome Android
18
Safari iOS
3
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
<div class="demo-ld"> <p class="unsupported">Your browser does not support light-dark(), so the card below stays unstyled.</p> <label class="switch"> <input type="checkbox" id="dark" role="switch"> <span class="track" aria-hidden="true"></span> Dark scheme </label> <article class="card"> <h2>Weekly report</h2> <p>Every color here is written once, as a light value and a dark value. Flip the switch: only <code>color-scheme</code> changes.</p> <ul class="chips"> <li class="a">light-dark(#fff, #14161c)</li> <li class="b">light-dark(#4338ca, #a5b4fc)</li> </ul> <div class="native"> <label>Name <input type="text" value="Ada"></label> <button type="button">Save</button> </div> </article></div>
Browser support
First browser version supporting the whole light-dark() feature
Chrome
123
Edge
123
Firefox
120
Safari
17.5
Chrome Android
123
Safari iOS
17.5
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The text-wrap: balance CSS declaration balances the length of each line when text is broken into multiple lines. Also known as headline balancing.
<section class="default-example" id="default-example"> <div class="whole-content-wrapper"> <p>Edit the text in the box:</p> <div class="transition-all" id="example-element"> <p contenteditable> Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptatem aut cum eum id quos est. </p> </div> </div></section>
web-features The writing-mode CSS property orients form elements (such as radio buttons, progress bars, or select menus) vertically when the writing mode is vertical-lr or vertical-rl. The direction CSS property sets whether inputs flow from top to bottom or bottom to top.
Vertical form controlsWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-rnd"> <p class="unsupported">This browser does not support random(), so the pieces and squares are not scattered.</p> <p class="hint">Every piece has the same rule and a different look. Reroll to create new elements: each gets new values.</p> <div class="controls"> <button type="button" id="reroll">Reroll</button> </div> <div class="stage" id="stage" aria-hidden="true"></div> <div class="rows"> <div> <p class="label"><code>random(8px, 30px)</code>: each element rolls its own size</p> <div class="row own" id="own" aria-hidden="true"></div> </div> <div> <p class="label"><code>random(--same, 8px, 30px)</code>: one shared name, one shared roll</p> <div class="row same" id="same" aria-hidden="true"></div> </div> </div></div>
Limited availability, moving since October 2026Lists
web-features The symbols() CSS function defines counter styles as a value of properties such as list-style. It's an inline alternative to the @counter-style CSS at-rule.
Limited availability, moving since October 2026Text
web-features The text-decoration-skip-spaces CSS property sets whether text decoration lines (such as underlines and overlines) skip over whitespace characters. You can use this to prevent decorations from being drawn under spaces, which is sometimes more visually appealing.
No demo written yet and no MDN example for this feature: read its definition through the links below.
Limited availability, moving since September 2026CSS
web-features The at-rule() function, when used with @supports, checks if a CSS at-rule is supported. For example @supports at-rule(@starting-style) checks if the @starting-style at-rule is supported.
web-features The frame-sizing CSS property sets the size of an <iframe> element to that of it contents, to avoid scrolling in the iframe. Embedded documents allow this with the <meta name="responsive-embedded-sizing"> element and request resizing in the embedding page by calling window.requestResize().
<h1>Responsive iframes — basic example</h1><iframe src="frame.html"></iframe><head> ... <meta name="responsive-embedded-sizing" /> ...</head><body> <h1>This is my frame</h1> <p>This is the content of my discontent.</p> <p>This is some more content.</p></body>
Limited availability, moving since September 2026Anchor positioning
web-features Anchor positioning places an element based on the position of another element. For example, you can place a tooltip next to the content it references.
Anchor positioningWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-anchor"> <p class="unsupported" role="note">Anchor positioning is not supported in this browser, so the tooltips cannot be placed next to their chips.</p> <fieldset class="side"> <legend>Preferred side</legend> <label><input type="radio" name="side" id="side-top" checked> Top</label> <label><input type="radio" name="side" id="side-right"> Right</label> <label><input type="radio" name="side" id="side-bottom"> Bottom</label> <label><input type="radio" name="side" id="side-left"> Left</label> </fieldset> <p class="hint">Hover or focus a chip, then scroll inside the box so a chip meets an edge: the tooltip flips.</p> <div class="box" tabindex="0" role="region" aria-label="Scrollable list of chips"> <ul class="grid"> <li class="item"><button type="button" class="chip" aria-describedby="t1">Margin</button><span class="tip" id="t1" role="tooltip">Space outside the border</span></li> <li class="item"><button type="button" class="chip" aria-describedby="t2">Border</button><span class="tip" id="t2" role="tooltip">The line around the box</span></li> <li class="item"><button type="button" class="chip" aria-describedby="t3">Padding</button><span class="tip" id="t3" role="tooltip">Space inside the border</span></li> <li class="item"><button type="button" class="chip" aria-describedby="t4">Content</button><span class="tip" id="t4" role="tooltip">Where the text and images live</span></li> <li class="item"><button type="button" class="chip" aria-describedby="t5">Inset</button><span class="tip" id="t5" role="tooltip">Offsets from the containing block</span></li> <li class="item"><button type="button" class="chip" aria-describedby="t6">Anchor</button><span class="tip" id="t6" role="tooltip">The element a tooltip sticks to</span></li> <li class="item"><button type="button" class="chip" aria-describedby="t7">Fallback</button><span class="tip" id="t7" role="tooltip">Plan B when there is no room</span></li> <li class="item"><button type="button" class="chip" aria-describedby="t8">Flip</button><span class="tip" id="t8" role="tooltip">Mirror to the other side</span></li> <li class="item"><button type="button" class="chip" aria-describedby="t9">Span</button><span class="tip" id="t9" role="tooltip">Cover several grid tiles</span></li> <li class="item"><button type="button" class="chip" aria-describedby="t10">Scope</button><span class="tip" id="t10" role="tooltip">Keeps one anchor name per chip</span></li> <li class="item"><button type="button" class="chip" aria-describedby="t11">Tether</button><span class="tip" id="t11" role="tooltip">Follows the chip while scrolling</span></li> <li class="item"><button type="button" class="chip" aria-describedby="t12">Grid</button><span class="tip" id="t12" role="tooltip">Three by three tiles around the anchor</span></li> <li class="item"><button type="button" class="chip" aria-describedby="t13">Center</button><span class="tip" id="t13" role="tooltip">The tile where the anchor sits</span></li> <li class="item"><button type="button" class="chip" aria-describedby="t14">Overflow</button><span class="tip" id="t14" role="tooltip">What the fallbacks try to avoid</span></li> <li class="item"><button type="button" class="chip" aria-describedby="t15">Viewport</button><span class="tip" id="t15" role="tooltip">The last resort boundary</span></li> <li class="item"><button type="button" class="chip" aria-describedby="t16">Popover</button><span class="tip" id="t16" role="tooltip">Pairs well with anchors</span></li> <li class="item"><button type="button" class="chip" aria-describedby="t17">Menu</button><span class="tip" id="t17" role="tooltip">A common anchored widget</span></li> <li class="item"><button type="button" class="chip" aria-describedby="t18">Tooltip</button><span class="tip" id="t18" role="tooltip">You are looking at one</span></li> </ul> </div></div>
Browser support
First browser version supporting the whole Anchor positioning feature
Chrome
No
Edge
No
Firefox
No
Safari
27
Chrome Android
No
Safari iOS
27
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Dui nunc mattis enim ut tellus elementum sagittis vitae et.</p><div class="anchor">⚓︎</div><div class="infobox"> <p>This is an information box.</p></div><p> Nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus. In arcu cursus euismod quis viverra nibh cras pulvinar. Vulputate ut pharetra sit amet aliquam.</p><p> Malesuada nunc vel risus commodo viverra maecenas accumsan lacus. Vel elit scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique. Porta lorem mollis aliquam ut porttitor. Turpis cursus in hac habitasse platea dictumst quisque. Dolor sit amet consectetur adipiscing elit. Ornare lectus sit amet est placerat. Nulla aliquet porttitor lacus luctus accumsan.</p>
Limited availability, moving since September 2026Selectors
web-features The s identifier in a CSS attribute selector matches attribute values case-sensitively in document languages like HTML where attribute values are case-insensitive.
No demo written yet and no MDN example for this feature: read its definition through the links below.
Browser support
First browser version supporting the whole Case-sensitive attribute selector feature
Chrome
No
Edge
No
Firefox
66
Safari
27
Chrome Android
No
Safari iOS
27
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
Limited availability, moving since September 2026Selectors
web-features The :heading and :heading() CSS pseudo-classes match headings of varying levels. The :heading pseudo-class matches any heading (<h1> through <h6>). The :heading() selector matches any of the given levels. For example, :heading(1, 2) matches headings level 1 and 2.
Live previewExample from MDN
:heading { color: tomato; font-style: italic;}
<h1>Mastering CSS</h1><h2>Chapter 1: Selectors</h2><p> A CSS selector is the part of a CSS rule that describes what elements in a document the rule will match.</p><h3>1.1 Pseudo-classes</h3><p> CSS pseudo-classes enable selecting elements based on information that lies outside of the document tree.</p>
Limited availability, moving since September 2026Layout
web-features The stretch CSS keyword expands a box as needed to fit its contents until the maximum size is reached, without preserving the content's preferred aspect ratio.
<section class="default-example" id="default-example"> <div class="transition-all" id="example-element"> This is a box where you can change the maximum height. <br />This will limit how tall the box can be, potentially causing an overflow. </div></section>
web-features The text-autospace CSS property sets whether and how to insert spaces in inter-script text (such as when mixing Latin and Chinese characters) and around punctuation.
Limited availability, moving since September 2026Scrolling
web-features The scroll-axis-lock property controls whether scrolling is locked to one dimension at a time or freely follows movement in two dimensions. By default, browsers may lock the scroll axis, ignoring minor perpendicular scrolling, when scrolling is nearly vertical or horizontal.
No demo written yet and no MDN example for this feature: read its definition through the links below.
Limited availability, moving since September 2026CSS
web-features The attr() CSS function, in the context of any property, returns the value of an attribute of an HTML element, with the option to return it as a specific type or unit. You can set a default value for missing or invalid attributes.
<blockquote cite="https://mozilla.org/en-US/about/"> Mozilla is working to put control of the internet back in the hands of the people using it.</blockquote><blockquote cite="https://web.dev/about/"> Build beautiful, accessible, fast, and secure websites that work cross-browser.</blockquote>
web-features The window-drag: move CSS declaration sets an element as a window drag handle, like a device's app title bar. You can use this to add click-and-drag areas to an installed progressive web app, often alongside window controls overlay.
No demo written yet and no MDN example for this feature: read its definition through the links below.
Limited availability, moving since August 2026Text
web-features The text-box CSS property sets the spacing above and below text based on a font's typographic features. For example, text-box: trim-both ex alphabetic trims the top to the top of the letter x and the bottom to the bottom of most letters, without descenders.
text-boxWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
Dashed chips belong to the same feature but this demo does not use them.
.demo-textbox { max-width: 50rem; margin-inline: auto; }.demo-textbox .pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 16px; }.demo-textbox .col { display: grid; justify-items: start; gap: 14px; padding: 14px; border: 2px solid #e2e8f0; border-radius: 14px; }.demo-textbox .col-trim { border-color: #4f46e5; }.demo-textbox h2 { margin: 0; font: 700 0.85rem ui-monospace, monospace; color: #334155; }/* The pink band is the content box: it shows exactly where the text box starts and ends. */.demo-textbox .tb { margin: 0; padding: 18px 28px; border: 0; border-radius: 12px; background: linear-gradient(#fda4af, #fda4af) content-box, #1e293b; color: #1b1b1b; font-family: system-ui, sans-serif; font-weight: 800; line-height: 1.6;}.demo-textbox .big { font-size: 4rem; letter-spacing: 0.04em; }.demo-textbox .btn { font-size: 1.4rem; cursor: pointer; }.demo-textbox .btn:hover { filter: brightness(1.1); }.demo-textbox .btn:focus-visible { outline: 3px solid #4f46e5; outline-offset: 3px; }/* Trim the leading above the capital letters and below the baseline. */.demo-textbox .col-trim .tb { text-box: trim-both cap alphabetic; }.demo-textbox .note { margin: 14px 0 0; color: #555; font-size: 0.9rem; }.demo-textbox .unsupported { display: none; margin: 0 0 12px; padding: 8px 12px; border-radius: 8px; background: #fef3c7; color: #78350f; }@supports not (text-box: trim-both cap alphabetic) { .demo-textbox .unsupported { display: block; }}
<div class="demo-textbox"> <p class="unsupported" role="status">This browser does not support <code>text-box</code>. Both columns look the same.</p> <div class="pair"> <section class="col"> <h2>text-box: normal</h2> <p class="tb big">NEXT</p> <button type="button" class="tb btn">Continue</button> </section> <section class="col col-trim"> <h2>text-box: trim-both cap alphabetic</h2> <p class="tb big">NEXT</p> <button type="button" class="tb btn">Continue</button> </section> </div> <p class="note">Same padding on both sides. The pink band is the text box.</p></div>
Browser support
First browser version supporting the whole text-box feature
Chrome
133
Edge
133
Firefox
No
Safari
18.2
Chrome Android
133
Safari iOS
18.2
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The picture-in-picture API allow websites to create a floating, always-on-top video window. Also known as PiP or pop-out video.
Live previewExample from MDN
abbr { color: #860304; font-weight: bold; transition: color 0.5s ease;}@media (hover: hover) { abbr:hover { color: #001ca8; transition-duration: 0.5s; }}@media not all and (hover: hover) { abbr::after { content: " (" attr(title) ")"; }}
<p> <abbr title="National Aeronautics and Space Administration">NASA</abbr> is a U.S. government agency that is responsible for science and technology related to air and space.</p>
web-features The url() CSS function accepts a cross-origin() modifier to control cross-origin resource sharing (CORS) when requesting the URL. For example, url("https://example.com" cross-origin(anonymous))) does not send credentials to the URL.
Live previewExample from MDN
ul { font-size: 3rem; margin: 0;}ul { list-style: outside url("https://mdn.github.io/shared-assets/images/examples/firefox-logo.svg");}
Limited availability, moving since June 2026Flexbox
web-features The flex-wrap: balance CSS declaration distributes items in a multi-line flex container such that each line has about the same number of items.
web-features The named-feature() function, when used with @supports, checks if a named CSS behavior is supported. The CSS behavior names are defined by specification. For example, @supports named-feature(anchor-position-follows-transforms) checks whether anchor-positioning applies after transforms."
web-features The url() CSS function accepts a referrer-policy() modifier to choose which referrer to send when requesting the URL. For example, `url("https://example.com" referrer-policy(no-referrer)) does not send a referrer to the URL.
Live previewExample from MDN
ul { font-size: 3rem; margin: 0;}ul { list-style: outside url("https://mdn.github.io/shared-assets/images/examples/firefox-logo.svg");}
web-features The text-fit CSS property scales text to fill the inline size of its container. You can use this to grow or shrink headlines, captions, or pull quotes to fit a container.
<input type="range" min="0.4" max="1" value="1" step="0.01" aria-label="adjust the width of the page" /><div> <h1>My heading</h1> <h2>My subtitle: a bit longer, may need shrinking</h2></div>
Limited availability, moving since June 2026Color types
web-features The AccentColor and AccentColorText CSS system color values are the background color and text color of accented user interface controls. To prevent browser fingerprinting, browsers may (and often do) use fixed color values that do not reflect user customization or theming choices.
Live previewExample from MDN
.button { border: 0; padding: 10px; box-shadow: -2px -2px 5px gray, 2px 2px 5px gray;}@media (forced-colors: active) { .button { /* Use a border instead, since box-shadow is forced to 'none' in forced-colors mode */ border: 2px ButtonBorder solid; }}
Limited availability, moving since June 2026CSS object models
web-features A CSSPseudoElement object represents a pseudo-element and its context in the document tree. You get an instance through the pseudo() method of Element or CSSPseudoElement objects or the pseudoTarget property of some events.
No demo written yet and no MDN example for this feature: read its definition through the links below.
Browser support
First browser version supporting the whole CSSPseudoElement feature
Chrome
149
Edge
149
Firefox
No
Safari
No
Chrome Android
149
Safari iOS
No
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The column-rule and row-rule CSS properties display decorative lines between columns and rows of a flex, grid, or multi-column layout. The rule-break, rule-outset, and rule-paint-order properties control the appearance of these lines.
web-features Interest invokers, registered by the interestfor HTML attribute, trigger events and actions on a target element when a user shows interest in the element, through behaviors such as hover, focus, or long-press. Pseudo-elements apply styles to sources and targets of interest.
Live previewExample from MDN
.delay { interest-delay: 1s 2s;}
<button interestfor="mypopover">Button</button><p id="mypopover" popover>Hover tooltip</p><form> <input type="checkbox" id="apply-delay" /> <label for="apply-delay"> Apply an <code>interest-delay</code> of <code>1s 2s</code> </label></form>
<button id="showDialogBtn">Show a dialog</button><dialog id="favDialog"> <form method="dialog"> <p>The background shown outside of this dialog is a backdrop.</p> <button id="confirmBtn">Close the dialog</button> </form></dialog>
Limited availability, moving since May 2026Container queries
web-features The @container style() CSS at-rule and if(style()) CSS function queries accept a range syntax, such as >, <, >=, <=, to query for inexact values.
Live previewExample from MDN
span { display: block; text-align: center;}.card { margin: 10px; border: 2px dotted; font-size: 1.5em;}.post { border: 2px solid;}/* A container context based on inline size */.post { container-type: inline-size;}/* Apply styles if the container is narrower than 650px */@container (width < 650px) { .card { width: 50%; background-color: lightgray; font-size: 1em; }}
<p> «For a moment, nothing happened. Then, after a second or so, nothing continued to happen.»</p><p class="hanging"> «For a moment, nothing happened. Then, after a second or so, nothing continued to happen.»</p><p class="hanging right"> «For a moment, nothing happened. Then, after a second or so, nothing continued to happen.»</p>
Limited availability, moving since April 2026Media elements
web-features The :playing, :paused, :seeking, :buffering, :stalled, :muted, and :volume-locked CSS pseudo-classes match <audio> and <video> elements based on their state.
No demo written yet and no MDN example for this feature: read its definition through the links below.
<section class="default-example" id="default-example"> <div class="example-container"> <div class="box"> This is a scrollable container. Michaelmas term lately over, and the Lord Chancellor sitting in Lincoln's Inn Hall. Implacable November weather. As much mud in the streets as if the waters had but newly retired from the face of the earth. <br /><br /> Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. </div> <div id="example-element"> This is the inner container. Focus on this container, scroll to the bottom and when you reach the bottom keep scrolling. <p> If you have <code class="language-css">overscroll-behavior: auto;</code> selected the outer container will start to scroll. </p> If you have <code class="language-css">overscroll-behavior: contain;</code> selected, the outer container will not scroll unless you move your cursor out of the inner container and try to perform scroll on the outer container. </div> </div></section>
web-features The border-shape CSS property sets the geometry of the border box, changing the shape of any applicable border, border image, focus outline, or shadow.
Limited availability, moving since April 2026View transitions
web-features The startViewTransition() method of an Element object starts a view transition that affects only that element's DOM tree. You can use this to run separate elements' transitions concurrently.
<button>Update DOM</button><section> <div class="change-me"><span>I can change</span></div> <div class="change-me"> <span>I can change</span> <div class="change-me"><span>I can change</span></div> </div> <div class="change-me"><span>I can change</span></div></section>
const btn = document.querySelector("button");const divs = document.querySelectorAll("div");function updateDivs() { divs.forEach((div) => { if (div.firstElementChild.textContent === "I can change") { div.firstElementChild.textContent = "I have changed"; div.style.color = "white"; div.style.backgroundColor = "black"; } else { div.firstElementChild.textContent = "I can change"; div.style.color = "black"; div.style.backgroundColor = "white"; } });}btn.addEventListener("click", handleClick);function handleClick(e) { if (!document.startViewTransition) { updateDivs(); return; } document.startViewTransition(() => { updateDivs(); });}
Limited availability, moving since March 2026Layout
web-features The display: grid-lanes and display: inline-grid-lanes CSS declarations create a layout where items are tightly packed in parallel lanes. Items are placed one by one in the lane that has the most available space. Also known as masonry.
<p> Apply different <code>display</code> values on the dashed orange-bordered <code>div</code>, which contains three child elements.</p><section class="default-example" id="default-example"> <div class="example-container"> Some text A. <div id="example-element"> <div class="child">Child 1</div> <div class="child">Child 2</div> <div class="child">Child 3</div> </div> Some text B. </div></section>
Limited availability, moving since March 2026Scrolling
web-features Scroll-triggered animations start and stop CSS animations when an element is within or outside a scrolling range. It's an alternative to applying styles with the IntersectionObserver API. Not to be confused with scroll-driven animations.
<div class="animated">I am animated</div>...<div class="trigger">I create the trigger</div>...<div class="animated">I am animated</div><p> Fusce dictum ex quis ipsum consectetur placerat. Cras sed lectus ex. Quisque purus dolor, vulputate ac mi eget, commodo varius odio. Suspendisse faucibus ipsum vel libero finibus, in placerat nibh congue. Sed iaculis, metus et euismod posuere, mi diam vestibulum felis, ac vulputate eros ipsum id justo. Etiam a tincidunt purus. Maecenas semper sed enim at blandit. Aenean ut sagittis lorem, eget gravida purus. Phasellus eleifend, lectus nec pulvinar facilisis, dui dolor feugiat odio, iaculis tempor felis est non tortor. In suscipit lorem efficitur molestie tempus. Integer sit amet neque et risus iaculis sodales sed eget diam. Quisque sodales nunc sapien, vitae lacinia ex luctus quis. Maecenas scelerisque scelerisque elit eu consequat. Etiam ac tristique tellus, sed tincidunt velit.</p><p> Fusce dictum ex quis ipsum consectetur placerat. Cras sed lectus ex. Quisque purus dolor, vulputate ac mi eget, commodo varius odio. Suspendisse faucibus ipsum vel libero finibus, in placerat nibh congue. Sed iaculis, metus et euismod posuere, mi diam vestibulum felis, ac vulputate eros ipsum id justo. Etiam a tincidunt purus. Maecenas semper sed enim at blandit. Aenean ut sagittis lorem, eget gravida purus. Phasellus eleifend, lectus nec pulvinar facilisis, dui dolor feugiat odio, iaculis tempor felis est non tortor. In suscipit lorem efficitur molestie tempus. Integer sit amet neque et risus iaculis sodales sed eget diam. Quisque sodales nunc sapien, vitae lacinia ex luctus quis. Maecenas scelerisque scelerisque elit eu consequat. Etiam ac tristique tellus, sed tincidunt velit.</p><div class="trigger">I create the trigger</div><p> Fusce dictum ex quis ipsum consectetur placerat. Cras sed lectus ex. Quisque purus dolor, vulputate ac mi eget, commodo varius odio. Suspendisse faucibus ipsum vel libero finibus, in placerat nibh congue. Sed iaculis, metus et euismod posuere, mi diam vestibulum felis, ac vulputate eros ipsum id justo. Etiam a tincidunt purus. Maecenas semper sed enim at blandit. Aenean ut sagittis lorem, eget gravida purus. Phasellus eleifend, lectus nec pulvinar facilisis, dui dolor feugiat odio, iaculis tempor felis est non tortor. In suscipit lorem efficitur molestie tempus. Integer sit amet neque et risus iaculis sodales sed eget diam. Quisque sodales nunc sapien, vitae lacinia ex luctus quis. Maecenas scelerisque scelerisque elit eu consequat. Etiam ac tristique tellus, sed tincidunt velit.</p><p> Fusce dictum ex quis ipsum consectetur placerat. Cras sed lectus ex. Quisque purus dolor, vulputate ac mi eget, commodo varius odio. Suspendisse faucibus ipsum vel libero finibus, in placerat nibh congue. Sed iaculis, metus et euismod posuere, mi diam vestibulum felis, ac vulputate eros ipsum id justo. Etiam a tincidunt purus. Maecenas semper sed enim at blandit. Aenean ut sagittis lorem, eget gravida purus. Phasellus eleifend, lectus nec pulvinar facilisis, dui dolor feugiat odio, iaculis tempor felis est non tortor. In suscipit lorem efficitur molestie tempus. Integer sit amet neque et risus iaculis sodales sed eget diam. Quisque sodales nunc sapien, vitae lacinia ex luctus quis. Maecenas scelerisque scelerisque elit eu consequat. Etiam ac tristique tellus, sed tincidunt velit.</p>
Limited availability, moving since February 2026CSS
web-features The overflow-clip-margin CSS property sets how far overflow content may appear outside the bounds of an element before it's clipped by effects such as overflow: clip.
overflow-clip-marginWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
Limited availability, moving since February 2026Multi-column
web-features The column-wrap and column-height CSS properties control when columns in a multicolumn layout wrap or overflow. You can use this to constrain the height of columns within a taller box or to create two-dimensional column layouts.
Live previewExample from MDN
ol { column-width: 150px; gap: 2em; column-height: 3em;}
<ol> <li>One fish</li> <li>Two fish</li> <li>Red fish</li> <li>Blue fish</li> ...</ol><p>-- Dr. Seuss</p><ol> <li>One fish</li> <li>Two fish</li> <li>Red fish</li> <li>Blue fish</li> <li>Black fish</li> <li>Blue fish</li> <li>Old fish</li> <li>New fish.</li> <li>This one has a little star.</li> <li>This one has a little car.</li> <li>Say! What a lot</li> <li>Of fish there are.</li> <li>Yes. Some are red. And some are blue.</li> <li>Some are old. And some are new.</li> <li>Some are sad.</li> <li>And some are glad.</li> <li>And some are very, very bad.</li> <li>Why are they</li> <li>Sad and glad and bad?</li> <li>I do not know.</li> <li>Go ask your dad.</li> <li>Some are thin.</li> <li>And some are fat.</li> <li>The fat one has</li> <li>A yellow hat.</li> <li>From there to here, from here to there,</li> <li>Funny things</li> <li>Are everywhere.</li></ol><p>--Dr. Seuss</p>
<p class="none"> <code>text-justify: none</code> —<br />Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ornare maximus vehicula. Duis nisi velit, dictum id mauris vitae, lobortis pretium quam. Quisque sed nisi pulvinar, consequat justo id, feugiat leo. Cras eu elementum dui.</p><p class="auto"> <code>text-justify: auto</code> —<br />Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ornare maximus vehicula. Duis nisi velit, dictum id mauris vitae, lobortis pretium quam. Quisque sed nisi pulvinar, consequat justo id, feugiat leo. Cras eu elementum dui.</p><p class="dist"> <code>text-justify: distribute</code> —<br />Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ornare maximus vehicula. Duis nisi velit, dictum id mauris vitae, lobortis pretium quam. Quisque sed nisi pulvinar, consequat justo id, feugiat leo. Cras eu elementum dui.</p><p class="word"> <code>text-justify: inter-word</code> —<br />Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ornare maximus vehicula. Duis nisi velit, dictum id mauris vitae, lobortis pretium quam. Quisque sed nisi pulvinar, consequat justo id, feugiat leo. Cras eu elementum dui.</p><p class="char"> <code>text-justify: inter-character</code> —<br />Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ornare maximus vehicula. Duis nisi velit, dictum id mauris vitae, lobortis pretium quam. Quisque sed nisi pulvinar, consequat justo id, feugiat leo. Cras eu elementum dui.</p>
web-features The caret-shape CSS property sets the shape of the insertion caret, the symbol that shows where the next character is to be inserted or deleted.
Limited availability, moving since January 2026Container queries
web-features Container scroll-state queries with the @container scroll-state(...) at-rule apply styles to an element based on the sticky positioning, snapped, scrollable, and scrolled state of the container.
Live previewExample from MDN
span { display: block; text-align: center;}.card { margin: 10px; border: 2px dotted; font-size: 1.5em;}.post { border: 2px solid;}/* A container context based on inline size */.post { container-type: inline-size;}/* Apply styles if the container is narrower than 650px */@container (width < 650px) { .card { width: 50%; background-color: lightgray; font-size: 1em; }}
// The color input only changes one custom property. CSS does the rest.const demo = document.querySelector(".demo-accent");const pick = document.getElementById("pick");const hex = document.getElementById("hex");pick.addEventListener("input", () => { demo.style.setProperty("--accent", pick.value); hex.textContent = pick.value;});
Browser support
First browser version supporting the whole accent-color feature
Chrome
93
Edge
93
Firefox
92
Safari
26.2
Chrome Android
No
Safari iOS
26.2
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
Limited availability, moving since December 2025Anchor positioning
web-features Anchor position container queries with the @container anchored(fallback: …) at-rule apply styles to an element based on the element's anchor position.
Live previewExample from MDN
span { display: block; text-align: center;}.card { margin: 10px; border: 2px dotted; font-size: 1.5em;}.post { border: 2px solid;}/* A container context based on inline size */.post { container-type: inline-size;}/* Apply styles if the container is narrower than 650px */@container (width < 650px) { .card { width: 50%; background-color: lightgray; font-size: 1em; }}
Limited availability, moving since October 2025Scroll markers
web-features The :target-current CSS pseudo-class selects the active scroll marker (as in ::scroll-marker), while the :target-after and :target-before pseudo-classes select the inactive markers preceding and following the active scroll marker.
<nav id="toc"> <ol> <li><a href="#intro">Introduction</a></li> <li><a href="#ch1">Chapter 1</a></li> <li><a href="#ch2">Chapter 2</a></li> <li><a href="#ch3">Chapter 3</a></li> <li><a href="#ch4">Chapter 4</a></li> </ol></nav><section id="intro" class="chapter"> <h1>Prose of the century</h1> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. </p></section><section id="ch1" class="chapter"> <h2>Chapter 1</h2> <!-- ... --></section><section id="ch2" class="chapter"> <h2>Chapter 2</h2> <!-- ... --></section><!-- ... --><nav id="toc"> <ol> <li><a href="#intro">Introduction</a></li> <li><a href="#ch1">Chapter 1</a></li> <li><a href="#ch2">Chapter 2</a></li> <li><a href="#ch3">Chapter 3</a></li> <li><a href="#ch4">Chapter 4</a></li> </ol></nav><section id="intro" class="chapter"> <h1>My story</h1> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. </p></section><section id="ch1" class="chapter"> <h2>Chapter 1</h2> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. </p> <p> Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien. </p> <p> Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. </p></section><section id="ch2" class="chapter"> <h2>Chapter 2</h2> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. </p> <p> Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien. </p></section><section id="ch3" class="chapter"> <h2>Chapter 3</h2> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. </p> <p> Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien. </p></section><section id="ch4" class="chapter"> <h2>Chapter 4</h2> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. </p> <p> Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien. </p></section>
Limited availability, moving since September 2025Anchor positioning
web-features The anchor() and anchor-size() CSS functions animate or transition on changes such as the anchor box moving or the anchor element changing.
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p><p> Nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus. In arcu cursus euismod quis viverra nibh cras pulvinar. Vulputate ut pharetra sit amet aliquam.</p><div class="anchor">⚓︎</div><div class="infobox" id="infobox1"> <p>This is the first infobox.</p></div><div class="infobox" id="infobox2"> <p>This is the second infobox.</p></div><p> Malesuada nunc vel risus commodo viverra maecenas accumsan lacus. Vel elit scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique. Porta lorem mollis aliquam ut porttitor. Turpis cursus in hac habitasse platea dictumst quisque. Dolor sit amet consectetur adipiscing elit. Ornare lectus sit amet est placerat. Nulla aliquet porttitor lacus luctus accumsan.</p>
Limited availability, moving since September 2025CSS
web-features The dynamic-range-limit CSS property controls the peak luminance of high dynamic range content. You can use this to coordinate the apparent brightness of HDR and SDR content.
Live previewExample from MDN
img { dynamic-range-limit: standard; transition: dynamic-range-limit 0.6s;}img:hover,img:focus { dynamic-range-limit: no-limit;}img { max-height: 100vh;}@media not (dynamic-range: high) { body::before { content: "Your device may not display the image at full brightness."; background-color: wheat; display: block; text-align: center; }}@supports not (dynamic-range-limit: standard) { body::before { content: "Your browser doesn't support the dynamic-range-limit property."; background-color: wheat; display: block; text-align: center; }}
<img src="https://mdn.github.io/shared-assets/images/examples/ultra-hdr.jpg" alt="A subway station platform with bright white overhead strip lights" tabindex="0" />
<div class="demo-pretty"> <p class="unsupported" role="status">This browser does not support <code>text-wrap: pretty</code>. Both columns wrap the default way.</p> <p class="hint">Drag the bottom-right corner of the box to resize it.</p> <div class="stage"> <section class="col"> <h2>text-wrap: auto</h2> <p class="body body-auto">Good typography is mostly invisible. When the lines of a paragraph break well, you simply read, and you never notice the work behind it. When they break badly, one lonely word shows up at the end of it all.</p> <p class="stat" aria-live="polite">Last line: <strong>-</strong></p> </section> <section class="col"> <h2>text-wrap: pretty</h2> <p class="body body-pretty">Good typography is mostly invisible. When the lines of a paragraph break well, you simply read, and you never notice the work behind it. When they break badly, one lonely word shows up at the end of it all.</p> <p class="stat" aria-live="polite">Last line: <strong>-</strong></p> </section> </div></div>
// Reads back how many words sit on the last line of each paragraph.function lastLineWords(p) { const node = p.firstChild; const text = node.textContent; const words = [...text.matchAll(/\S+/g)]; const range = document.createRange(); const tops = words.map((m) => { range.setStart(node, m.index); range.setEnd(node, m.index + m[0].length); return range.getClientRects()[0].top; }); const last = tops[tops.length - 1]; return tops.filter((t) => Math.abs(t - last) < 2).length;}function update() { for (const p of document.querySelectorAll(".body")) { const n = lastLineWords(p); const out = p.parentElement.querySelector(".stat strong"); out.textContent = n === 1 ? "1 word" : n + " words"; out.className = n === 1 ? "lone" : "ok"; }}let timer;new ResizeObserver(() => { clearTimeout(timer); timer = setTimeout(update, 120);}).observe(document.querySelector(".stage"));update();
Browser support
First browser version supporting the whole text-wrap: pretty feature
Chrome
117
Edge
117
Firefox
No
Safari
26
Chrome Android
117
Safari iOS
26
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
Limited availability, moving since September 2025Scroll markers
web-features The scroll-target-group CSS property sets the container where anchor links act as scroll markers. Using selectors such as :target-current, you can style elements when a target has scrolled into view. It's an alternative to the ::scroll-marker-group pseudo-element, which generates scroll markers.
<nav id="toc"> <ol> <li><a href="#intro">Introduction</a></li> <li><a href="#ch1">Chapter 1</a></li> <li><a href="#ch2">Chapter 2</a></li> <li><a href="#ch3">Chapter 3</a></li> <li><a href="#ch4">Chapter 4</a></li> </ol></nav><section id="intro" class="chapter"> <h1>Prose of the century</h1> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. </p></section><section id="ch1" class="chapter"> <h2>Chapter 1</h2> <!-- ... --></section><section id="ch2" class="chapter"> <h2>Chapter 2</h2> <!-- ... --></section><!-- ... --><nav id="toc"> <ol> <li><a href="#intro">Introduction</a></li> <li><a href="#ch1">Chapter 1</a></li> <li><a href="#ch2">Chapter 2</a></li> <li><a href="#ch3">Chapter 3</a></li> <li><a href="#ch4">Chapter 4</a></li> </ol></nav><section id="intro" class="chapter"> <h1>My story</h1> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. </p></section><section id="ch1" class="chapter"> <h2>Chapter 1</h2> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. </p> <p> Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien. </p> <p> Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. </p></section><section id="ch2" class="chapter"> <h2>Chapter 2</h2> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. </p> <p> Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien. </p></section><section id="ch3" class="chapter"> <h2>Chapter 3</h2> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. </p> <p> Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien. </p></section><section id="ch4" class="chapter"> <h2>Chapter 4</h2> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. </p> <p> Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien. </p></section>
web-features The @function CSS at-rule defines a custom function that takes CSS values or custom properties as arguments, and returns a CSS value. It can be based on conditional logic such as by using the @media at-rule.
@functionWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
web-features The corner-shape CSS property sets the shape of an element's corners when using border-radius, allowing for shapes other than rounded corners. For example, corner-shape: squircle is a shape in between a square and rounded corner.
corner-shapeWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<p class="no-support"> Your Browser does not support <code>font-variant-emoji</code>. This image shows how it is rendered with support.</p><img class="no-support" src="./font-variant-emoji-example.jpg" alt="a telephone emoji show as text, black and white next to a telephone emoji shown as emoji full color and graphical representation" /><section class="emojis"> <div class="emoji"> <h2>text presentation</h2> <div class="text-presentation">☎</div> </div> <div class="emoji"> <h2>emoji presentation</h2> <div class="emoji-presentation">☎</div> </div></section>
web-features The viewport segment CSS environment variables and media features, and the viewport.segments API, allow you to adapt your layout to devices where the display is split, such as on foldable devices.
Live previewExample from MDN
abbr { color: #860304; font-weight: bold; transition: color 0.5s ease;}@media (hover: hover) { abbr:hover { color: #001ca8; transition-duration: 0.5s; }}@media not all and (hover: hover) { abbr::after { content: " (" attr(title) ")"; }}
<p> <abbr title="National Aeronautics and Space Administration">NASA</abbr> is a U.S. government agency that is responsible for science and technology related to air and space.</p>
web-features The reading-flow CSS property sets the order in which flex or grid elements are rendered to speech or reached via focus navigation. The reading-order property overrides this order.
reading-flowWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-rf"> <fieldset class="controls"> <legend>reading-flow</legend> <label><input type="radio" name="rf" id="rf-normal" checked> normal</label> <label><input type="radio" name="rf" id="rf-rows"> grid-rows</label> <label><input type="radio" name="rf" id="rf-columns"> grid-columns</label> <label><input type="radio" name="rf" id="rf-order"> source-order + reading-order</label> </fieldset> <p class="hint">Click a card, then press Tab. Letters show the order in the HTML.</p> <div class="grid"> <button type="button" class="a">A</button> <button type="button" class="b">B</button> <button type="button" class="c">C</button> <button type="button" class="d">D</button> <button type="button" class="e">E</button> <button type="button" class="f">F</button> </div> <p class="trail">Focus order: <output id="trail">none yet</output> <button type="button" id="reset">Clear</button></p> <p class="unsupported">reading-flow is not supported in this browser, so Tab always follows the HTML order.</p></div>
// Records the order in which the cards receive focus.var trail = document.getElementById("trail");var seen = [];function show() { trail.textContent = seen.length ? seen.join(" > ") : "none yet"; }document.querySelector(".demo-rf .grid").addEventListener("focusin", function (e) { if (e.target.tagName === "BUTTON") { seen.push(e.target.textContent); show(); }});document.getElementById("reset").addEventListener("click", function () { seen = []; show(); });document.querySelectorAll(".demo-rf input").forEach(function (r) { r.addEventListener("change", function () { seen = []; show(); });});
Browser support
First browser version supporting the whole reading-flow feature
Chrome
137
Edge
137
Firefox
No
Safari
No
Chrome Android
137
Safari iOS
No
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
Limited availability, moving since April 2025Multi-column
web-features The ::column CSS pseudo-element represents the individual columns of a multi-column layout container. Columns can only be styled with scroll snap CSS properties and can also have a ::scroll-marker pseudo-element, which scrolls to the column when activated.
Limited availability, moving since April 2025Scrolling
web-features The ::scroll-button(<dir>) CSS pseudo-element is a focusable button which scrolls its originating scroll container element in the specified direction.
::scroll-buttonWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="sb"> <p class="unsupported" role="note">Your browser does not support scroll buttons. The carousel still scrolls, but the arrow buttons are missing.</p> <p class="sb-hint">Use the arrow buttons. They switch off at both ends.</p> <ul class="sb-carousel" aria-label="Carousel with scroll buttons"> <li><span class="sb-n">A</span><span>Aurora</span></li> <li><span class="sb-n">B</span><span>Basalt</span></li> <li><span class="sb-n">C</span><span>Coral</span></li> <li><span class="sb-n">D</span><span>Dune</span></li> <li><span class="sb-n">E</span><span>Ember</span></li> </ul></div>
Browser support
First browser version supporting the whole ::scroll-button feature
Chrome
135
Edge
135
Firefox
No
Safari
No
Chrome Android
135
Safari iOS
No
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
Limited availability, moving since April 2025Text wrap
web-features The hyphenate-limit-chars CSS property sets the number of characters in a word before it is hyphenated and the minimum number of characters on either side of the hyphen.
<div class="container"> <p id="ex1">juxtaposition and acknowledgement</p> <p id="ex2">juxtaposition and acknowledgement</p> <p id="ex3">juxtaposition and acknowledgement</p> <p id="ex4">juxtaposition and acknowledgement</p></div>
web-features The interactivity: inert CSS declaration makes an element and its descendants inert, like when using the inert HTML attribute. Inert elements can't be focused or clicked, their text can't be selected or found using the browser's find-in-page feature.
Limited availability, moving since April 2025Scroll markers
web-features A scroll marker scrolls a container to a scroll target. The ::scroll-marker CSS pseudo-element selects a scroll marker in a ::scroll-marker-group pseudo-element, generated before or after the scroll container. You can use them to navigate and style tables of contents, tab panels, and carousels.
Scroll markersWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="sm"> <p class="unsupported" role="note">Your browser does not support scroll markers. The carousel still scrolls, but the dots are missing.</p> <p class="sm-hint">Swipe, scroll or click a dot. With the dots focused, use the arrow keys.</p> <ul class="sm-carousel" aria-label="Carousel with scroll markers"> <li><span class="sm-n">1</span><span>Mountains</span></li> <li><span class="sm-n">2</span><span>Lakes</span></li> <li><span class="sm-n">3</span><span>Forests</span></li> <li><span class="sm-n">4</span><span>Deserts</span></li> <li><span class="sm-n">5</span><span>Coasts</span></li> </ul></div>
Browser support
First browser version supporting the whole Scroll markers feature
Chrome
135
Edge
135
Firefox
No
Safari
No
Chrome Android
135
Safari iOS
No
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
Limited availability, moving since March 2025Selectors
web-features The :has-slotted CSS pseudo-class matches <slot> elements where the fallback content is not shown. The pseudo-class matches any slotted content, including white space, text nodes, or elements.
No demo written yet and no MDN example for this feature: read its definition through the links below.
Limited availability, moving since February 2025Scrolling
web-features The scroll-initial-target: nearest CSS declaration sets the initial scroll position of its scroll container to the top of the element, much like scrolling to a URL fragment.
web-features The device posture API and the device-posture CSS media feature reflect the physical posture of a device, such as whether a foldable device is folded or unfolded.
Live previewExample from MDN
abbr { color: #860304; font-weight: bold; transition: color 0.5s ease;}@media (hover: hover) { abbr:hover { color: #001ca8; transition-duration: 0.5s; }}@media not all and (hover: hover) { abbr::after { content: " (" attr(title) ")"; }}
<p> <abbr title="National Aeronautics and Space Administration">NASA</abbr> is a U.S. government agency that is responsible for science and technology related to air and space.</p>
Limited availability, moving since December 2024View transitions
web-features The @view-transition CSS rule sets whether a document opts-in to transitions between documents in a multi-page application. Both the old and new document must opt-in for a transition to be triggered.
No demo written yet and no MDN example for this feature: read its definition through the links below.
web-features The box-decoration-break CSS property sets whether box decorations, such as borders or backgrounds, of an element divided across a page, column, or region wraps each fragment or splits across the break.
Limited availability, moving since October 2024Layout
web-features The justify-self CSS property aligns an item along a container's inline axis in block layouts, like it does in grid layouts. Likewise, the justify-items property sets a default justify-self value for all items in a container in a block layout.
Limited availability, moving since September 2024CSS
web-features The calc-size() CSS function computes mathematical expressions that include height and width keyword values, for example calc-size(fit-content, size / 2). Not to be confused with the calc() CSS function, which cannot use keyword values.
calc-size()Written for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-cs"> <p class="unsupported">This browser does not support calc-size(), so the panel stays closed.</p> <p class="hint">Open the panel, then drag the factor. The height is the content height times the factor, and it animates.</p> <div class="controls"> <label class="switch"><input type="checkbox" id="open"> Open</label> <label class="factor">Factor <input type="range" id="factor" min="0.25" max="1.5" step="0.25" value="1"></label> <output id="expr" for="factor open">height: calc-size(auto, size * 1)</output> </div> <section class="panel" aria-label="Panel with a computed height"> <div class="inner"> <h3>Content height</h3> <p>The panel reads the natural height of what is inside it, multiplies it, and lands exactly there.</p> <p>Below 1 the content is cut. Above 1 the panel keeps extra room. At every step the height stays a real, animatable length.</p> </div> </section></div>
Limited availability, moving since September 2024Transitions (CSS)
web-features The interpolate-size CSS property sets whether animations and transitions interpolate between a numeric value and a keyword value, such as from a fixed length to auto or fit-content.
interpolate-sizeWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-is"> <p class="unsupported">This browser does not support interpolate-size, so both panels jump open.</p> <p class="hint">Open both panels. Same CSS, same transition, one property apart.</p> <label class="switch"><input type="checkbox" id="open"> Open both panels</label> <div class="pair"> <section class="box numeric"> <h3><code>numeric-only</code> (default)</h3> <div class="panel" id="panel-a"> <div class="inner"> <p>The height goes from 0 to auto. Auto is a keyword, not a number, so the browser has nothing to interpolate and the panel snaps.</p> </div> </div> </section> <section class="box smooth"> <h3><code>allow-keywords</code></h3> <div class="panel" id="panel-b"> <div class="inner"> <p>The height goes from 0 to auto. With the keyword allowed, the browser computes the real content height and animates to it.</p> </div> </div> </section> </div></div>
Browser support
First browser version supporting the whole interpolate-size feature
Chrome
129
Edge
129
Firefox
No
Safari
No
Chrome Android
129
Safari iOS
No
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
Limited availability, moving since September 2024CSS
web-features You can animate elements between display: none and any other display value or animate between content-visibility: hidden and any other content-visibility value. This also applies to transitions.
display animationWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
web-features The text-spacing-trim CSS property controls spacing around CJK characters, avoiding excessive whitespace when using full-width punctuation characters.
Limited availability, moving since March 2024Selectors
web-features The ::spelling-error and ::grammar-error CSS pseudo-elements match text that is highlighted as misspelled and grammatically incorrect, respectively.
Limited availability, moving since January 2024CSS
web-features The display: ruby CSS declaration renders an element with the box layout of a <ruby> HTML element. Child elements may use equivalents to <ruby> internal elements such as display: ruby-base for <rb>.
<p> Apply different <code>display</code> values on the dashed orange-bordered <code>div</code>, which contains three child elements.</p><section class="default-example" id="default-example"> <div class="example-container"> Some text A. <div id="example-element"> <div class="child">Child 1</div> <div class="child">Child 2</div> <div class="child">Child 3</div> </div> Some text B. </div></section>
<div class="demo-palette"> <p class="unsupported" role="status">This browser does not support <code>font-palette</code>. The text below shows the first palette only.</p> <p class="nofont" role="status">The demo colour font could not be loaded in this frame.</p> <p class="hint">Hover the title to pause it. Drag the slider to mix two palettes yourself.</p> <section class="card"> <h2 class="title animated">FONT PALETTE</h2> <p class="caption"><code>@keyframes</code> from palette to palette</p> </section> <section class="card"> <p class="title mixed">ANIMATION</p> <p class="caption"><code>palette-mix()</code> at your pace</p> <p class="slider"><label for="mix">Ocean in the mix</label> <input type="range" id="mix" min="0" max="100" value="40"> <output id="mix-out" for="mix">40%</output></p> </section></div>
// "Block Color": a tiny colour font (COLR + CPAL, two palettes) embedded as base64, so the demo loads no file.// The CSS only needs its family name, "Block Color".const FONT = "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";const demo = document.querySelector(".demo-palette");const mix = document.getElementById("mix");const out = document.getElementById("mix-out");const bytes = Uint8Array.from(atob(FONT), (c) => c.charCodeAt(0));const face = new FontFace("Block Color", bytes.buffer);face.load().then( () => document.fonts.add(face), () => demo.classList.add("no-font"));mix.addEventListener("input", () => { demo.style.setProperty("--mix", mix.value); out.textContent = mix.value + "%";});
Browser support
First browser version supporting the whole font-palette animation feature
Chrome
121
Edge
121
Firefox
No
Safari
No
Chrome Android
121
Safari iOS
No
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
Limited availability, moving since January 2024Layout
web-features The page-orientation CSS property sets the rotation of a page after pagination. This allows pages with the same size declaration to display with different orientations.
Limited availability, moving since December 2023Clipping, shapes, and masking
web-features The mask-border CSS property sets how the edges of an element are masked. It is a shorthand for mask-border-outset, mask-border-repeat, mask-border-slice, mask-border-source, and mask-border-width.
Limited availability, moving since December 2023CSS object models
web-features The numeric factory functions, such as CSS.px() or CSS.kHz(), return a CSSUnitValue representing a CSS number value (as in 12px or 440kHz).
No demo written yet and no MDN example for this feature: read its definition through the links below.
Browser support
First browser version supporting the whole Numeric factory functions feature
Chrome
66
Edge
79
Firefox
No
Safari
16.4
Chrome Android
66
Safari iOS
16.4
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
Limited availability, moving since October 2023Media queries
web-features The prefers-reduced-transparency CSS media query sets styles based on whether the user prefers to reduce the amount of transparent effects on their device, for example to improve contrast and legibility.
Live previewExample from MDN
abbr { color: #860304; font-weight: bold; transition: color 0.5s ease;}@media (hover: hover) { abbr:hover { color: #001ca8; transition-duration: 0.5s; }}@media not all and (hover: hover) { abbr::after { content: " (" attr(title) ")"; }}
<p> <abbr title="National Aeronautics and Space Administration">NASA</abbr> is a U.S. government agency that is responsible for science and technology related to air and space.</p>
Limited availability, moving since October 2023Text wrap
web-features The word-break: auto-phrase CSS declaration specifies that wrapping should occur at natural phrase boundaries, especially in CJK languages.
Limited availability, moving since September 2023Font synthesis
web-features The font-synthesis-position CSS property sets whether or not the browser should synthesize subscript and superscript typefaces when they're missing from the font.
<p> These are the default position <span class="super">superscript</span>, position <span class="sub">subscript</span>, <strong>bold</strong> and <em>oblique</em> typefaces.</p><p class="no-syn"> The positions <span class="super">superscript</span> and <span class="sub">subscript</span> typeface is turned off here but not the <strong>bold</strong> and <em>oblique</em> typefaces (on browsers that support <code>font-synthesis-position</code>).</p>
Limited availability, moving since September 2023CSS
web-features The overlay CSS property, used as an allow-discrete CSS transition, prevents a top layer element, such as a popover or a <dialog>, from being removed from the top layer before it has finished animating. You can't set the value of the overlay property; only use it as transition property.
Live previewExample from MDN
html { font-family: "Helvetica", "Arial", sans-serif;}[popover]:popover-open { opacity: 1; transform: scaleX(1);}[popover] { font-size: 1.2rem; padding: 10px; /* Final state of the exit animation */ opacity: 0; transform: scaleX(0); transition: opacity 0.7s, transform 0.7s, overlay 0.7s allow-discrete, display 0.7s allow-discrete; /* Equivalent to transition: all 0.7s allow-discrete; */}/* Needs to be included after the previous [popover]:popover-open rule to take effect, as the specificity is the same */@starting-style { [popover]:popover-open { opacity: 0; transform: scaleX(0); }}/* Transition for the popover's backdrop */[popover]::backdrop { background-color: transparent; transition: display 0.7s allow-discrete, overlay 0.7s allow-discrete, background-color 0.7s; /* Equivalent to transition: all 0.7s allow-discrete; */}[popover]:popover-open::backdrop { background-color: rgb(0 0 0 / 25%);}/* Nesting selectors (&) cannot represent pseudo-elements, so this starting-style rule cannot be nested. */@starting-style { [popover]:popover-open::backdrop { background-color: transparent; }}
<button popovertarget="mypopover">Show the popover</button><div popover="auto" id="mypopover">I'm a Popover! I should animate.</div>
web-features The baseline-source CSS property controls how inline-level boxes with multiple lines of text are aligned with the surrounding text. By default, which typographic baseline is used depends on the display property value.
Limited availability, moving since February 2023CSS
web-features The initial-letter CSS property sets the number of lines the first letter of an element occupies. You can use the property to make a raised capital or drop cap.
<p class="normal">Initial letter is normal</p><p class="onefive">Initial letter occupies 1.5 lines</p><p class="three">Initial letter occupies 3 lines</p>
<div class="demo-ac"> <fieldset class="controls"> <legend>align-content</legend> <label><input type="radio" name="ac" id="ac-start"> start</label> <label><input type="radio" name="ac" id="ac-center" checked> center</label> <label><input type="radio" name="ac" id="ac-end"> end</label> </fieldset> <p class="hint">The box below is a plain block. No flex, no grid. Drag its bottom-right corner to change its height.</p> <div class="box"> <h2>Aligned in a block</h2> <p>This text sits in a normal <code>div</code>. The box decides where its content goes.</p> </div> <p class="unsupported">Block layout alignment is not supported in this browser, so the content stays at the top.</p></div>
// Old engines accept align-content but ignore it on a block: measure to be sure.(function () { var probe = document.createElement("div"); probe.style.cssText = "display:block;height:100px;align-content:center;position:absolute;visibility:hidden"; probe.innerHTML = "<div style='height:10px'></div>"; document.body.appendChild(probe); var works = probe.firstChild.offsetTop > 0; probe.remove(); if (!works) document.querySelector(".demo-ac .unsupported").setAttribute("data-off", "");})();
Browser support
First browser version supporting the whole align-content in block layouts feature
Chrome
123
Edge
123
Firefox
125
Safari
17.4
Chrome Android
123
Safari iOS
17.4
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The transform-box CSS property sets the position and dimensions of the reference box relative to which an element's transformations are calculated.
Live previewExample from MDN
svg { width: 80vh; border: 1px solid #d9d9d9; position: absolute; margin: auto; inset: 0;}#box { transform-origin: 50% 50%; /* anything other than `0 0` to see the effect */ transform-box: fill-box; animation: rotate-box 3s linear infinite;}@keyframes rotate-box { to { transform: rotate(360deg); }}
web-features The paint-order CSS property sets the z-order of strokes, fills, and (in SVG content) markers. For example, paint-order: markers stroke fill; draws the markers, then stroke on top of markers, then fill on top of both markers and stroke.
paint-orderWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
web-features The white-space-collapse CSS property sets whether new line characters are shown as line breaks, and whether multiple consecutive spaces are all displayed or combined.
white-space-collapseWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-wsc"> <p class="unsupported" role="status">This browser does not support <code>white-space-collapse</code>. All boxes collapse spaces the default way.</p> <p class="field"> <label for="source">Type spaces and line breaks here</label> <textarea id="source" rows="6" spellcheck="false">Spaces collapse. Indented line.Line twoA long run of spaces: end of the run.</textarea> </p> <div class="grid"> <section class="box"> <h2>collapse</h2> <div class="out collapse">Spaces collapse. Indented line.Line twoA long run of spaces: end of the run.</div> </section> <section class="box"> <h2>preserve</h2> <div class="out preserve">Spaces collapse. Indented line.Line twoA long run of spaces: end of the run.</div> </section> <section class="box"> <h2>preserve-breaks</h2> <div class="out preserve-breaks">Spaces collapse. Indented line.Line twoA long run of spaces: end of the run.</div> </section> <section class="box"> <h2>preserve-spaces</h2> <div class="out preserve-spaces">Spaces collapse. Indented line.Line twoA long run of spaces: end of the run.</div> </section> <section class="box"> <h2>break-spaces</h2> <div class="out break-spaces">Spaces collapse. Indented line.Line twoA long run of spaces: end of the run.</div> </section> </div></div>
Widely available since July 2026Clipping, shapes, and masking
web-features The rect() CSS function creates a rectangle shape with insets from the edges of an element. The xywh() CSS function creates a rectangle shifted by an x and y distance. They can be used with clip-path and shape-outside.
rect() and xywh()Written for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
.demo-rect { max-width: 860px; margin-inline: auto; color: #1b1b1b; }.demo-rect .hint { margin: 0 0 14px; color: #4b5563; }.demo-rect .unsupported { display: none; margin: 0 0 12px; padding: 8px 12px; border: 1px solid #f59e0b; border-radius: 8px; background: #fef3c7; color: #78350f;}@supports not (clip-path: xywh(0 0 10px 10px)) { .demo-rect .unsupported { display: block; }}.demo-rect .trio { display: flex; flex-wrap: wrap; gap: 20px; }.demo-rect figure { margin: 0; width: 240px; max-width: 100%; }.demo-rect figcaption { margin-top: 8px; font-size: 0.85rem; line-height: 1.4; }.demo-rect code { display: block; font-weight: 700; color: #4338ca; }.demo-rect .frame { width: 220px; height: 150px; max-width: 100%; border: 1px dashed #6b7280; background: repeating-conic-gradient(#e5e7eb 0 25%, #fff 0 50%) 0 0 / 16px 16px;}.demo-rect .scene { width: 100%; height: 100%; background: radial-gradient(circle at 72% 34%, #fff7c2 0 11%, #fbbf24 12% 17%, transparent 18%), linear-gradient(transparent 68%, #166534 68%), linear-gradient(#1e3a8a, #ec4899 75%); transition: clip-path 0.6s ease;}/* Same rectangle three ways, with the same rounded corners. */.demo-rect .s-inset { clip-path: inset(20px 40px 30px 20px round 14px); }.demo-rect .s-rect { clip-path: rect(20px 180px 120px 20px round 14px); }.demo-rect .s-xywh { clip-path: xywh(20px 20px 160px 100px round 14px); }/* Reveal: each syntax animates to the full box in its own terms. auto in rect() means the edge of the box: 0 for top and left, 100% for the others. */.demo-rect .s-inset:hover,.demo-rect:has(#full:checked) .s-inset { clip-path: inset(0 0 0 0 round 0); }.demo-rect .s-rect:hover,.demo-rect:has(#full:checked) .s-rect { clip-path: rect(auto auto auto auto round 0); }.demo-rect .s-xywh:hover,.demo-rect:has(#full:checked) .s-xywh { clip-path: xywh(0 0 100% 100% round 0); }.demo-rect .reveal { margin: 18px 0 0; display: flex; gap: 8px; align-items: center; }.demo-rect .reveal input { width: 1.1rem; height: 1.1rem; accent-color: #4f46e5; }@media (prefers-reduced-motion: reduce) { .demo-rect .scene { transition: none; }}
<div class="demo-rect"> <p class="unsupported">rect() and xywh() are not supported in this browser. The three scenes show whole, unclipped.</p> <p class="hint">Three syntaxes, one rectangle. The checkered area is the box that is clipped away.</p> <div class="trio"> <figure> <div class="frame"><div class="scene s-inset"></div></div> <figcaption><code>inset(20px 40px 30px 20px)</code> offsets from each edge</figcaption> </figure> <figure> <div class="frame"><div class="scene s-rect"></div></div> <figcaption><code>rect(20px 180px 120px 20px)</code> top, right, bottom, left, all from the top left</figcaption> </figure> <figure> <div class="frame"><div class="scene s-xywh"></div></div> <figcaption><code>xywh(20px 20px 160px 100px)</code> x, y, width, height</figcaption> </figure> </div> <p class="reveal"> <input id="full" type="checkbox"> <label for="full">Reveal the whole scene (or hover a scene)</label> </p></div>
Browser support
First browser version supporting the whole rect() and xywh() feature
Chrome
119
Edge
119
Firefox
122
Safari
17.2
Chrome Android
119
Safari iOS
17.2
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
<div class="demo-has"> <p class="unsupported" role="status">This browser does not support :has(), so the parent styling below cannot work.</p> <form class="panel"> <header> <h2>Pick your add-ons</h2> <label class="switch"><input type="checkbox" id="dark" role="switch"> Dark panel</label> </header> <fieldset class="grid"> <legend class="sr">Add-ons</legend> <label class="card"><input type="checkbox" name="addon" value="backups"><span class="title">Backups</span><span class="sub">Nightly snapshots</span></label> <label class="card"><input type="checkbox" name="addon" value="domains"><span class="title">Domains</span><span class="sub">Custom address</span></label> <label class="card"><input type="checkbox" name="addon" value="analytics"><span class="title">Analytics</span><span class="sub">No cookies</span></label> <label class="card"><input type="checkbox" name="addon" value="support"><span class="title">Support</span><span class="sub">Answers in a day</span></label> </fieldset> <p class="summary" aria-live="polite"><span class="none">Tick a card. The card, the grid, this line and the panel all react to a child.</span><span class="some"></span></p> <button type="reset">Clear</button> </form></div>
Browser support
First browser version supporting the whole :has() feature
Chrome
105
Edge
105
Firefox
121
Safari
15.4
Chrome Android
105
Safari iOS
15.4
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The counter-set CSS property creates (and optionally sets a value for) a counter, the numbers for a series of headings or ordered list items.
<section class="default-example" id="default-example"> <div class="transition-all" id="chapters"> <h1>Alice's Adventures in Wonderland</h1> <h2>Down the Rabbit-Hole</h2> <h2 id="example-element">The Pool of Tears</h2> <h2>A Caucus-Race and a Long Tale</h2> <h2>The Rabbit Sends in a Little Bill</h2> </div></section>
web-features The linear() easing function for animations and transitions interpolates linearly between the control points, and can be used to approximate complex easing functions, such as a bounce effect.
linear() easingWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-dir"> <p class="unsupported" role="status">This browser does not support :dir(), so the bubbles below keep one look for both directions.</p> <div class="bar" role="group" aria-label="Direction of the chat"> <span>Chat direction</span> <button type="button" data-dir="ltr" aria-pressed="true">LTR</button> <button type="button" data-dir="rtl" aria-pressed="false">RTL</button> </div> <section class="chat" id="chat" dir="ltr" aria-label="Messages"> <p class="msg">This bubble inherits the direction.</p> <p class="msg">So does this one. Use the buttons.</p> <p class="msg" dir="auto">Hello, this one is detected as left to right.</p> <p class="msg" dir="auto" lang="ar">مرحبا، هذه الرسالة تُقرأ من اليمين إلى اليسار.</p> <p class="msg" dir="auto" lang="he">שלום, ההודעה הזאת נקראת מימין לשמאל.</p> <p class="send"><a class="next" href="#next">Next</a></p> </section> <div class="compose"> <label for="draft">Type here, then try Arabic or Hebrew letters</label> <textarea id="draft" dir="auto" rows="2">Hello</textarea> </div></div>
const chat = document.getElementById("chat");const buttons = document.querySelectorAll(".bar button");for (const button of buttons) { button.addEventListener("click", () => { chat.dir = button.dataset.dir; for (const other of buttons) other.setAttribute("aria-pressed", String(other === button)); });}
Browser support
First browser version supporting the whole :dir() feature
Chrome
120
Edge
120
Firefox
49
Safari
16.4
Chrome Android
120
Safari iOS
16.4
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
Widely available since June 2026Clipping, shapes, and masking
web-features The mask CSS property (and several longhand properties) partially or completely hides an element according to the shape and depth of an image.
MasksWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
web-features The scripting CSS media query sets styles based on whether scripting such as JavaScript is available. Values are enabled if scripting is available, initial-only if scripting is only available on page load (for example, printed content), or none.
Live previewExample from MDN
abbr { color: #860304; font-weight: bold; transition: color 0.5s ease;}@media (hover: hover) { abbr:hover { color: #001ca8; transition-duration: 0.5s; }}@media not all and (hover: hover) { abbr::after { content: " (" attr(title) ")"; }}
<p> <abbr title="National Aeronautics and Space Administration">NASA</abbr> is a U.S. government agency that is responsible for science and technology related to air and space.</p>
web-features The lh CSS length unit corresponds to the requested line height, the computed value of the line-height property. Some lines may be higher than this based on their content.
lh unitWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
.demo-lh { --accent: #4f46e5; max-width: 46rem; margin-inline: auto; }.demo-lh .controls { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 18px; margin: 0 0 12px; }.demo-lh fieldset { display: flex; gap: 4px 14px; margin: 0; padding: 4px 12px 8px; border: 1px solid #cbd5e1; border-radius: 10px; }.demo-lh legend { padding-inline: 4px; font: 0.85rem ui-monospace, monospace; color: #475569; }.demo-lh label { cursor: pointer; }.demo-lh input:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }/* The stage sets the line height. Everything inside is measured in lh, so one value drives the whole page. */.demo-lh .stage { --line: 1.6; box-sizing: border-box; padding: 1lh 1.25rem; font-size: 1rem; line-height: var(--line); border: 2px solid #cbd5e1; border-radius: 12px; background: #fff; transition: line-height 0.35s ease;}.demo-lh:has(#lh-tight:checked) .stage { --line: 1.3; }.demo-lh:has(#lh-loose:checked) .stage { --line: 2; }/* A ruled grid, one line per 1lh. */.demo-lh:has(#grid:checked) .stage { background-image: linear-gradient(to bottom, transparent calc(1lh - 1px), #f43f5e66 calc(1lh - 1px)); background-size: 100% 1lh; background-origin: content-box; background-clip: content-box;}/* Margins and heights in lh stay on the grid. In a line-height declaration, lh refers to the parent. */.demo-lh h2 { margin: 0; font-size: 1.35rem; line-height: 2lh; color: var(--accent); }.demo-lh p { margin: 0 0 1lh; }.demo-lh .art { height: 4lh; margin: 0 0 1lh; border-radius: 10px; background: repeating-linear-gradient(135deg, #6366f1 0 1lh, #a5b4fc 1lh 2lh);}.demo-lh blockquote { margin: 0 0 1lh; padding-inline: 1rem; border-inline-start: 4px solid var(--accent); font-style: italic; }.demo-lh .stage > :last-child { margin-block-end: 0; }@media (prefers-reduced-motion: reduce) { .demo-lh .stage { transition: none; } }.demo-lh .unsupported { display: none; margin: 0 0 10px; padding: 8px 12px; border-radius: 8px; background: #fef3c7; color: #78350f; }@supports not (height: 1lh) { .demo-lh .unsupported { display: block; }}/* A <length> unit: lh is the computed line-height of the element it is used on. */
<div class="demo-lh"> <p class="unsupported" role="status">This browser does not support the <code>lh</code> unit. Spacing falls back to fixed values and the grid stays hidden.</p> <div class="controls"> <fieldset> <legend>line-height</legend> <label><input type="radio" name="lh" id="lh-tight"> 1.3</label> <label><input type="radio" name="lh" id="lh-normal" checked> 1.6</label> <label><input type="radio" name="lh" id="lh-loose"> 2</label> </fieldset> <label class="toggle"><input type="checkbox" id="grid" checked> Show the 1lh grid</label> </div> <article class="stage"> <h2>Rhythm without maths</h2> <p>Every gap on this page is a whole number of lines. Change the line height and the heading, the picture and the quote all move with the text, still on the grid.</p> <div class="art" role="img" aria-label="A striped banner, four lines tall"></div> <blockquote>Margins, paddings and heights are written in lh, so they follow the line height.</blockquote> <p>Nothing is recalculated by hand.</p> </article></div>
Browser support
First browser version supporting the whole lh unit feature
Chrome
109
Edge
109
Firefox
120
Safari
16.4
Chrome Android
109
Safari iOS
16.4
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The :user-valid and :user-invalid pseudo-classes match form controls that have been marked as valid or invalid based on their validation constraints.
:user-valid and :user-invalidWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-user"> <p class="unsupported" role="status">This browser does not support :user-valid and :user-invalid, so only the left field below reacts.</p> <form class="form" id="signup"> <p class="hint">Click into each field, type, then leave it. Compare the two email fields.</p> <div class="row"> <div class="field old"> <label for="e1">Email, styled with <code>:invalid</code></label> <input id="e1" type="email" required placeholder="you@example.com"> <p class="msg">Red from the first paint, before you typed anything.</p> </div> <div class="field new"> <label for="e2">Email, styled with <code>:user-invalid</code></label> <input id="e2" type="email" required placeholder="you@example.com"> <p class="msg bad">Enter a valid email address.</p> <p class="msg good">Looks good.</p> </div> </div> <div class="row"> <div class="field new"> <label for="u">Username, 3 to 12 letters</label> <input id="u" type="text" required minlength="3" maxlength="12" pattern="[A-Za-z]+" placeholder="ada"> <p class="msg bad">Use 3 to 12 letters, no digits.</p> <p class="msg good">Available.</p> </div> <div class="field new"> <label for="a">Age, 18 or more</label> <input id="a" type="number" required min="18" max="120" placeholder="18"> <p class="msg bad">You must be between 18 and 120.</p> <p class="msg good">Thanks.</p> </div> </div> <div class="actions"> <button type="submit">Create account</button> <button type="reset">Reset</button> <p class="status" role="status"></p> </div> </form></div>
// The preview is sandboxed: stop the real submit and just confirm.const form = document.getElementById("signup");const note = form.querySelector(".status");form.addEventListener("submit", (event) => { event.preventDefault(); note.textContent = "Account created.";});form.addEventListener("reset", () => { note.textContent = ""; });
Browser support
First browser version supporting the whole :user-valid and :user-invalid feature
Chrome
119
Edge
119
Firefox
88
Safari
16.5
Chrome Android
119
Safari iOS
16.5
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The @counter-style CSS at-rule sets custom counter styles for list items. For example, you can use a sequence of specific symbols instead of numbers for an ordered list.
@counter-styleWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
web-features The contain-intrinsic-size CSS property sets the intrinsic size of an element. When using size containment, the browser will lay out the element as if it had a single child of this size.
web-features The hyphens CSS property controls when long words are broken by line wrapping. Although called hyphens, the property applies to word-splitting behavior across languages, such as customary spelling changes or the use of other characters. Support for non-English languages varies significantly.
HyphenationWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-hyphens"> <p class="unsupported" role="status">This browser does not support <code>hyphens</code>. Long words stay whole.</p> <p class="hint">Drag the bottom-right corner of the box to narrow it. Only the first word has a soft hyphen (&shy;).</p> <div class="stage" lang="en"> <section class="sample"> <h2>hyphens: none</h2> <p class="text none">Extra­ordinarily incomprehensible telecommunications responsibilities overshadowed the enthusiastic international conference.</p> </section> <section class="sample"> <h2>hyphens: manual</h2> <p class="text manual">Extra­ordinarily incomprehensible telecommunications responsibilities overshadowed the enthusiastic international conference.</p> </section> <section class="sample"> <h2>hyphens: auto</h2> <p class="text auto">Extra­ordinarily incomprehensible telecommunications responsibilities overshadowed the enthusiastic international conference.</p> </section> </div></div>
Browser support
First browser version supporting the whole Hyphenation feature
Chrome
88
Edge
88
Firefox
43
Safari
17
Chrome Android
55
Safari iOS
17
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The image-set() CSS function provides a set of images at different resolutions or pixel densities, which the browser can pick from, depending on the device capabilities.
image-set()Written for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-set"> <p class="unsupported">image-set() is not supported in this browser. The picture boxes below stay empty.</p> <p class="status">Screen density: <output id="dpr">1x</output>. Zoom the page with Ctrl and plus (or minus) to change it.</p> <div class="row"> <figure> <div class="art picked" role="img" aria-label="Picture chosen by the browser from the set"></div> <figcaption><code>image-set()</code> with both images: the browser picks</figcaption> </figure> <figure> <div class="art only-1x" role="img" aria-label="The 1x picture alone"></div> <figcaption>The 1x image alone</figcaption> </figure> <figure> <div class="art only-2x" role="img" aria-label="The 2x picture alone"></div> <figcaption>The 2x image alone</figcaption> </figure> </div></div>
const out = document.getElementById("dpr");function show() { out.value = `${Number(window.devicePixelRatio.toFixed(2))}x`;}window.addEventListener("resize", show);show();
Browser support
First browser version supporting the whole image-set() feature
Chrome
113
Edge
113
Firefox
89
Safari
17
Chrome Android
113
Safari iOS
17
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The overflow-block and overflow-inline CSS media queries set styles based on the way a device displays content that's larger than the viewport or page area. For example, a laptop lets users scroll to reveal content, while a printer displays overflowing content on additional pages.
No demo written yet and no MDN example for this feature: read its definition through the links below.
web-features The update CSS media query sets styles based on whether and how fast the user's device can modify display after it has been rendered. For example, you can avoid animations on devices that aren't fast enough to display them smoothly.
Live previewExample from MDN
abbr { color: #860304; font-weight: bold; transition: color 0.5s ease;}@media (hover: hover) { abbr:hover { color: #001ca8; transition-duration: 0.5s; }}@media not all and (hover: hover) { abbr::after { content: " (" attr(title) ")"; }}
<p> <abbr title="National Aeronautics and Space Administration">NASA</abbr> is a U.S. government agency that is responsible for science and technology related to air and space.</p>
web-features The subgrid value for the grid-template-columns and grid-template-rows properties allows a grid item to inherit the grid definition of its parent grid container.
SubgridWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-subgrid"> <label class="switch"><input type="checkbox" id="use-subgrid" checked> Use subgrid</label> <div class="cards"> <article class="card"> <h2>Starter</h2> <p>One project and a shared inbox.</p> <p class="price">$0</p> </article> <article class="card"> <h2>Professional plan for growing teams</h2> <p>Unlimited projects, roles, audit history and priority support for the whole team, with single sign-on and a custom domain.</p> <p class="price">$24</p> </article> <article class="card"> <h2>Enterprise</h2> <p>Custom limits, a dedicated manager and an uptime guarantee.</p> <p class="price">Talk to us</p> </article> </div> <p class="unsupported">Subgrid is not supported in this browser, so each card lays out on its own.</p></div>
Browser support
First browser version supporting the whole Subgrid feature
Chrome
117
Edge
117
Firefox
71
Safari
16
Chrome Android
117
Safari iOS
16
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The display CSS property accepts multiple keyword values, such as inline flex or block flow, to explicitly set an element's inner and outer layout mode. Also known as 2-value, multi-keyword, or multiple value syntax.
Two-value display propertyWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-display"> <div class="controls"> <fieldset> <legend>Outside: how it sits among its neighbours</legend> <label><input type="radio" name="outer" id="o-block" checked> block</label> <label><input type="radio" name="outer" id="o-inline"> inline</label> </fieldset> <fieldset> <legend>Inside: how it lays out its children</legend> <label><input type="radio" name="inner" id="i-flow"> flow</label> <label><input type="radio" name="inner" id="i-flow-root"> flow-root</label> <label><input type="radio" name="inner" id="i-flex" checked> flex</label> <label><input type="radio" name="inner" id="i-grid"> grid</label> </fieldset> </div> <p class="code" aria-live="polite"></p> <p class="sample"> Text before the box, <span class="box"><i>One</i><i>Two</i><i>Three</i></span> and text after it, long enough to show whether the box shares the line or takes its own. </p> <p class="unsupported">Two-value display is not supported in this browser, so the box keeps its default display.</p></div>
Browser support
First browser version supporting the whole Two-value display property feature
Chrome
115
Edge
115
Firefox
70
Safari
15
Chrome Android
115
Safari iOS
15
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
<div class="demo-ac"> <p class="unsupported">This browser does not support animation-composition, so all three bars behave like replace.</p> <p class="hint">Same keyframes, same starting transform. The dashed bar is the underlying value, the solid bar is animated.</p> <div class="lanes"> <figure class="lane replace"> <div class="track"><span class="ghost"></span><span class="bar"></span></div> <figcaption><code>replace</code>: the keyframe wins, the rotation is lost</figcaption> </figure> <figure class="lane add"> <div class="track"><span class="ghost"></span><span class="bar"></span></div> <figcaption><code>add</code>: the keyframe is appended, it slides along the tilted axis</figcaption> </figure> <figure class="lane accumulate"> <div class="track"><span class="ghost"></span><span class="bar"></span></div> <figcaption><code>accumulate</code>: the values are summed, the rotation stays</figcaption> </figure> </div></div>
Browser support
First browser version supporting the whole animation-composition feature
Chrome
112
Edge
112
Firefox
115
Safari
16
Chrome Android
112
Safari iOS
16
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features The of syntax for the :nth-child() and :nth-last-child() CSS functional pseudo-classes match elements by the relative position of elements, counted from the first or last sibling matching a selector list.
:nth-child() of <selector>Written for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
web-features The color-mix() function mixes two colors in a given color space and by a given amount. Commonly, lighter or darker variations of a color are created by mixing with white or black.
color-mix()Written for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
web-features The color() function picks a color from a given color space. Wide gamut color spaces like display-p3 allow showing more vibrant and saturated colors than the standard srgb color space.
web-features The CIE Lab color space expresses colors in terms of lightness and how red/green and blue/yellow a color is. LCH is a variant of Lab with polar coordinates. These color spaces can be used with the CSS color(), lab(), and lch() functions. Also known as CIELAB and CIELCH.
web-features The Oklab color space expresses colors in terms of lightness and how red/green and blue/yellow a color is, aiming to match how humans perceive colors. OkLCh is a variant of Oklab with polar coordinates. These color spaces can be used with the CSS oklab() and oklch() functions.
Oklab and OkLChWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
Widely available since September 2025Font synthesis
web-features The font-synthesis-small-caps CSS property sets whether or not the browser should synthesize small caps typefaces when they're missing from the font.
<p class="english"> These are the default <span class="small-caps">small-caps</span>, <strong>bold</strong>, and <em>oblique</em> typefaces.</p><p class="english no-syn"> The <span class="small-caps">small-caps</span> typeface is turned off here but not the <strong>bold</strong> and <em>oblique</em> typefaces.</p>
Widely available since September 2025Font synthesis
web-features The font-synthesis-style CSS property sets whether or not the browser should synthesize italic and oblique typefaces when they're missing from the font.
<p class="english"> This is the default <em>oblique typeface</em> and <strong>bold typeface</strong>.</p><p class="english no-syn"> The <em>oblique typeface</em> is turned off here but not the <strong>bold typeface</strong>.</p>
Widely available since September 2025Font synthesis
web-features The font-synthesis-weight CSS property sets whether or not the browser should synthesize bold typefaces when they're missing from the font.
<p class="english"> This is the default <strong>bold typeface</strong> and <em>oblique typeface</em>.</p><p class="english no-syn"> The <strong>bold typeface</strong> is turned off here but not the <em>oblique typeface</em>.</p>
Widely available since September 2025Media queries
web-features The range syntax of CSS media queries allows you to use mathematical comparison operators such as <, >, <=, and >= to define a range of values for a media query. For example, (400px < width < 1000px) returns true if the viewport width is between 400px and 1000px.
Media query range syntaxWritten for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-mq"> <p class="unsupported">Range syntax in media queries is not supported in this browser, so no row below lights up.</p> <div class="panel"> <p class="now">Window width: <output id="w">0px</output></p> <p class="band"></p> </div> <p class="hint">Resize the browser window. Each row shows the new range syntax and the old way to write the same test.</p> <ul class="rows"> <li class="r1"><span class="lamp"></span><code class="new">(width < 480px)</code><code class="old">(max-width: 479.98px)</code></li> <li class="r2"><span class="lamp"></span><code class="new">(480px <= width < 720px)</code><code class="old">(min-width: 480px) and (max-width: 719.98px)</code></li> <li class="r3"><span class="lamp"></span><code class="new">(720px <= width < 960px)</code><code class="old">(min-width: 720px) and (max-width: 959.98px)</code></li> <li class="r4"><span class="lamp"></span><code class="new">(width >= 960px)</code><code class="old">(min-width: 960px)</code></li> </ul></div>
var out = document.getElementById("w");function update() { out.textContent = window.innerWidth + "px"; }update();window.addEventListener("resize", update);
Browser support
First browser version supporting the whole Media query range syntax feature
Chrome
104
Edge
104
Firefox
102
Safari
16.4
Chrome Android
104
Safari iOS
16.4
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
<section class="default-example" id="default-example"> <div class="transition-all" id="example-element"> This is a box with an outline around it. </div></section>
web-features The color-gamut media query sets styles based on the colors a device can display.
Live previewExample from MDN
abbr { color: #860304; font-weight: bold; transition: color 0.5s ease;}@media (hover: hover) { abbr:hover { color: #001ca8; transition-duration: 0.5s; }}@media not all and (hover: hover) { abbr::after { content: " (" attr(title) ")"; }}
<p> <abbr title="National Aeronautics and Space Administration">NASA</abbr> is a U.S. government agency that is responsible for science and technology related to air and space.</p>
Widely available since August 2025Container queries
web-features Container size queries with the @container (…) at-rule apply styles to an element based on a dimension of its container, such as width or height.
Container queries (size)Written for this site
The features this demo is built on. Solid chips are used in its code, click one to read its definition.
<div class="demo-cq"> <p class="hint">Drag the bottom-right corner of the dashed box. The card follows the box, not the window.</p> <div class="frame"> <article class="card"> <div class="art" aria-hidden="true"></div> <div class="body"> <span class="mode"></span> <h2 class="title">Aurora desk lamp</h2> <p class="text">Warm light that follows your day, with a soft dimmer and a wireless charging base.</p> <ul class="specs"> <li>12 W</li> <li>2700 to 6500 K</li> <li>USB-C</li> </ul> </div> <div class="buy"> <span class="price">$49</span> <button type="button">Add to cart</button> </div> </article> </div> <p class="unsupported">Container queries are not supported in this browser, so the card keeps its narrow layout.</p></div>
Browser support
First browser version supporting the whole Container queries (size) feature
Chrome
105
Edge
105
Firefox
110
Safari
16
Chrome Android
105
Safari iOS
16
First version supporting the feature as a whole, from web-features. Parts of it may have shipped earlier: see each key in the reference.
web-features MathML, or the Mathematical Markup Language, describes mathematical notation, such as expressions and formulas. Also known as MathML Core.
<p> Apply different <code>display</code> values on the dashed orange-bordered <code>div</code>, which contains three child elements.</p><section class="default-example" id="default-example"> <div class="example-container"> Some text A. <div id="example-element"> <div class="child">Child 1</div> <div class="child">Child 2</div> <div class="child">Child 3</div> </div> Some text B. </div></section>