# CSS Pro Tips

> Use when writing, reviewing, refactoring, or modernizing CSS/Tailwind with source-validated patterns for resets, box sizing, focus styles, centering, aspect ratios, selectors, layout, modern CSS, progressive enhancement, older-pattern modernization, MDN Baseline support buckets, user-preference media queries (reduced motion, contrast, forced colors, reduced transparency), container size and style queries, @property, popovers, View Transitions, custom highlights, scroll-state queries, text-box trim, and typed attr().

- Skill: `trac3r00/css-pro-tips` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add trac3r00/css-pro-tips`
- Raw SKILL.md: https://api.skillmd.com/api/skills/trac3r00/css-pro-tips/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- License: MIT (from PyModel/css-pro-tips; see LICENSE.txt)
- Author: trac3r00 (https://skillmd.com/u/trac3r00)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/trac3r00/css-pro-tips

---


# CSS Protips — Validated Skill

This skill is a source-validated update of the uploaded `css-protips` Markdown skill. It keeps the useful practical guidance, corrects current compatibility status where needed, adds explicit references for each claim, and now includes an expanded set of modern CSS tricks validated against MDN/web platform references.

## How to use this skill

Use this skill when writing, reviewing, or modernizing CSS. Prefer the “Validated patterns” section for day-to-day code. Use the “Modern CSS support buckets” section when deciding whether a feature can ship as normal production CSS or should be guarded with `@supports`. Use the “Retire or modernize older tips” section when replacing older CSS tricks with current native features.

## Validation rules used

1. **Compatibility language is source-bound.** “Widely available,” “Newly available,” and “Limited availability” follow MDN Baseline definitions unless a different source is named.
2. **Baseline is not QA.** Baseline says whether a web platform feature is broadly implemented across core browsers; it does not replace accessibility, keyboard, contrast, motion, performance, or project-specific testing.
3. **Progressive enhancement is required for limited or audience-dependent features.** If browser support is incomplete for your audience, ship a working fallback first, then add the enhanced rule with `@supports`.
4. **Do not turn tips into global rules blindly.** Global selectors such as `:empty`, `* + *`, or blanket resets can affect third-party widgets, CMS content, accessibility, or embedded components. Scope them unless the whole project explicitly opts in.

References: [MDN Baseline][ref-baseline], [MDN @supports][ref-supports].

## Validation window and status review dates

Statuses in this file were verified against live MDN Baseline banners, MDN browser-compat-data, and web.dev platform updates in **August 2026**.

Several statuses flip on known dates. Check these lines first when revalidating:

| Feature | Current status | Next expected change |
|---|---|---|
| `light-dark()` | Baseline Newly available, May 2024 | Widely available around November 2026 |
| `transition-behavior` | Baseline Newly available, August 2024 | Widely available around February 2027 |
| `@scope` | Baseline Newly available, March 2026 | Widely available around September 2028 |
| Anchor positioning | Baseline Newly available, January 2026 | Widely available around July 2028 |
| `field-sizing` | Baseline Newly available, June 2026 | Widely available around December 2028 |
| Container style queries, name-only container queries, `:open` | Baseline Newly available, May 2026 | Widely available around November 2028 |
| Scroll-driven animations | Limited, Firefox pending | Baseline whenever Firefox ships |
| `text-box-trim` | Chrome 133+, Safari 18.2+, Firefox 154+ | Baseline once the Firefox release is counted |

---

# Key corrections from the uploaded skill

| Area | Validated decision | Why |
|---|---|---|
| Baseline meaning | Keep the caveat. Baseline is a browser-compatibility signal only, not an accessibility/performance/QA guarantee. | MDN Baseline defines support buckets and explicitly says Baseline is not a substitute for accessibility, performance, and other tests. [MDN Baseline][ref-baseline] |
| Anchor positioning | Update from “Limited availability” to **Baseline 2026 Newly available** for core properties such as `anchor-name`, `position-area`, and `position-try-fallbacks`; still verify support floor and keep fallbacks for older audiences. | MDN now marks key anchor-positioning properties as Baseline 2026 Newly available. [MDN anchor-name][ref-anchor-name], [MDN position-area][ref-position-area], [MDN position-try-fallbacks][ref-position-try-fallbacks] |
| `field-sizing` | Update from “Limited availability” to **Baseline 2026 Newly available**; still use a fallback if your browser floor includes older browsers. | MDN marks `field-sizing` as Baseline 2026 Newly available. [MDN field-sizing][ref-field-sizing] |
| `accent-color` | Keep as **Limited availability**. Use as a progressive enhancement, not as the only brand-control styling mechanism. | MDN marks `accent-color` Limited availability. [MDN accent-color][ref-accent-color] |
| Scroll-driven animations | Keep as **progressive enhancement**. `animation-timeline` remains Limited availability, though Safari 26 now ships it and only Firefox is missing. | MDN marks `animation-timeline` Limited availability. [MDN animation-timeline][ref-animation-timeline], [WebKit scroll-driven animations][ref-webkit-sda] |
| `interpolate-size` / `calc-size()` | Keep as progressive enhancement. Do not treat native `height: auto` interpolation as Baseline. | MDN marks `interpolate-size` and `calc-size()` Limited availability/experimental. [MDN interpolate-size][ref-interpolate-size], [MDN calc-size][ref-calc-size] |
| `transition-behavior` | Use it for discrete transitions such as `display`; it does **not** by itself interpolate `height: 0` to `height: auto`. | MDN defines `transition-behavior` as enabling transitions for discrete animation properties. [MDN transition-behavior][ref-transition-behavior] |
| Generated-content commas/empty-link URLs | Keep only with accessibility/copy-paste caveats. Generated text from `content` may not behave like real DOM text. | MDN documents generated/replaced content and the `attr()` function, including accessibility-oriented alt text syntax. [MDN content][ref-content] |
| Native CSS nesting | Use it as normal production CSS. It reached Baseline Newly available in August 2023 and Widely available in February 2026; MDN confirms browser-native parsing, not preprocessor compilation. | [web.dev Baseline][ref-webdev-baseline], [MDN CSS nesting][ref-nesting] |

---

# Validated patterns

## 1. Use a CSS reset deliberately

A minimal reset can remove browser-default margin/padding and make layout more predictable. Prefer a project-owned reset rather than copy-pasting an aggressive global reset blindly.

```css
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
```

Validation: `box-sizing` is a widely available property. `border-box` makes the declared width/height include padding and border, which usually makes component sizing easier. [MDN box-sizing][ref-box-sizing]

## 2. Inherit `box-sizing` when components may need overrides

This variant sets the root sizing model once, then lets components inherit it.

```css
html {
  box-sizing: border-box;
}

*,
*::before,
*::after {
  box-sizing: inherit;
}
```

Validation: `box-sizing` supports `content-box` and `border-box`; inheriting from `html` is a safe pattern when a component needs to override sizing context locally. [MDN box-sizing][ref-box-sizing]

## 3. Use `all: unset` carefully for component resets

`all: unset` resets almost all CSS properties. It excludes `unicode-bidi`, `direction`, and custom properties. Because non-inherited properties go to their initial values, a button can lose its native display/box behavior. Restore layout and focus styles explicitly.

```css
button.reset {
  all: unset;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

button.reset:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 0.15em;
}
```

Use `all: revert` when the intent is “undo author styles and return toward UA/user defaults,” not “strip everything to a blank slate.”

Validation: MDN documents that `all` resets all properties except `unicode-bidi`, `direction`, and CSS custom properties. [MDN all][ref-all]

## 4. Prefer `:focus-visible` for keyboard focus styles

Use `:focus-visible` so keyboard users keep a visible focus indicator without forcing the same ring on every pointer click.

```css
:focus:not(:focus-visible) {
  outline: none;
}

:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 0.15em;
}
```

Validation: MDN describes `:focus-visible` as matching when the user agent determines that focus should be made evident, and notes that people need to know which element has focus. [MDN :focus-visible][ref-focus-visible]

## 5. Add unitless `line-height` to text containers

Set a readable unitless line height on `body` or on text-heavy containers.

```css
body {
  line-height: 1.5;
}
```

Validation: `line-height` sets the height of a line box, and MDN recommends unitless values because descendants inherit the number rather than a computed fixed length. [MDN line-height][ref-line-height]

## 6. Center with Grid or Flexbox

For page-level centering, Grid is concise. Use dynamic viewport block units on mobile when browser toolbars matter.

```css
.center-page {
  min-block-size: 100dvb;
  display: grid;
  place-items: center;
}
```

For flex layouts, set the container’s size and center on both axes.

```css
.center-flex {
  min-block-size: 100dvb;
  display: flex;
  align-items: center;
  justify-content: center;
}
```

Validation: `place-items` aligns items in block and inline directions at once. Flexbox centering uses `align-items` and `justify-content`. Dynamic viewport units represent viewport dimensions that update as browser UI expands/retracts; MDN also notes that dynamic units can resize during scrolling, so test the result. [MDN place-items][ref-place-items], [MDN flex alignment][ref-flex-align], [MDN viewport units][ref-viewport-units]

## 7. Use `aspect-ratio` for media boxes

Prefer `aspect-ratio` over wrapper/padding hacks for modern browsers.

```css
.media {
  aspect-ratio: 16 / 9;
  overflow: hidden;
}

.media > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
```

Validation: `aspect-ratio` sets a preferred width-to-height ratio; `object-fit: cover` preserves aspect ratio while filling and clipping as needed. [MDN aspect-ratio][ref-aspect-ratio], [MDN object-fit][ref-object-fit]

## 8. Use `:not()` for exclusion selectors

Use `:not()` to apply styles to everything except the excluded case.

```css
.nav li:not(:last-child) {
  border-inline-end: 1px solid #666;
}
```

Validation: `:not()` matches elements that are not represented by its argument selector list. [MDN :not][ref-not]

## 9. Use `:is()` for compact selector lists

Use `:is()` to reduce repeated selector groups.

```css
:is(section, article, aside, nav) :is(h1, h2, h3, h4, h5, h6) {
  margin-block-end: 0.5em;
}
```

Validation: `:is()` takes a selector list and selects elements matched by any selector in the list. MDN also documents its forgiving selector-list behavior. [MDN :is][ref-is]

## 10. Use `:where()` for low-specificity defaults

Use `:where()` when a default should be trivial to override.

```css
:where(a[href]:not([class])) {
  color: LinkText;
  text-decoration: underline;
}
```

Validation: `:where()` always has zero specificity, unlike `:is()`, whose specificity comes from the most specific selector in its arguments. [MDN :where][ref-where]

## 11. Use generated `content` only for non-critical presentation

Generated commas, visible URLs, and labels can be convenient, but they are not a replacement for semantic text in the DOM.

```css
ul.tags > li:not(:last-child)::after {
  content: ",";
}
```

Validation: the `content` property replaces or generates content; MDN documents `attr()` support and accessibility-related alternative text syntax. Treat generated content as presentational unless you have tested your assistive-technology target matrix. [MDN content][ref-content]

## 12. Use negative `:nth-child()` for first-N selection

```css
li:nth-child(-n + 3) {
  display: block;
}
```

Validation: `:nth-child()` matches elements by child index, and MDN documents the `An+B` syntax. [MDN :nth-child][ref-nth-child]

## 13. Use scoped `:nth-child(... of selector)` when sibling filtering matters

```css
li:nth-child(-n + 3 of .item) {
  display: block;
}
```

Validation: MDN documents the `of <complex-real-selector-list>` syntax, which counts only matching siblings for the formula. [MDN nth-child of selector][ref-nth-child-of]

## 14. Use SVG or masks for icons depending on recoloring needs

Use inline SVG or image SVGs for multicolor art. For monochrome, CSS-recolorable icons, use `mask` and paint with `currentColor`.

```css
.icon {
  inline-size: 1.5rem;
  block-size: 1.5rem;
  background-color: currentColor;
  mask: url("icon.svg") no-repeat center / contain;
}
```

Validation: CSS `mask` hides or clips parts of an element using a mask image; painting the masked element with `currentColor` lets the icon follow the text color. [MDN mask][ref-mask]

## 15. Scope flow spacing instead of using a global owl selector

The global `* + *` pattern is powerful but can leak into third-party widgets and internal component layouts. Scope it.

```css
.flow > * + * {
  margin-block-start: 1.5em;
}
```

Validation: adjacent sibling combinators are standard CSS selector behavior; logical `margin-block-start` follows the block axis for the writing mode. [MDN margin-inline/logical margin][ref-margin-inline], [MDN logical properties][ref-logical]

## 16. Use `max-height` disclosure only with caveats

A `max-height` transition works mechanically but animates toward an arbitrary ceiling, which can make timing feel wrong and can truncate content if the ceiling is too small.

```css
.disclosure {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
}

.disclosure.is-open {
  max-height: 50rem;
}
```

Validation: `max-height` caps used height, and `overflow` controls clipping/scroll behavior when content does not fit. MDN warns to ensure `max-height` content is not truncated/obscured when users zoom text. [MDN max-height][ref-max-height], [MDN overflow][ref-overflow]

## 17. Prefer grid-row disclosure for unknown-height content

For modern layouts, animate grid rows instead of guessing a `max-height` ceiling.

```css
.disclosure {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.3s ease;
}

.disclosure.is-open {
  grid-template-rows: 1fr;
}

.disclosure > * {
  min-block-size: 0;
  overflow: hidden;
}
```

Validation: CSS Grid defines row/column tracks, and grid track sizes are animatable in modern engines; still test because animation edge cases depend on content, overflow, and layout. [MDN CSS grid][ref-grid], [MDN grid-template-columns][ref-grid-template-columns]

## 18. Use `table-layout: fixed` only when the table width is known

```css
table.report {
  inline-size: 100%;
  table-layout: fixed;
}
```

Validation: MDN says the fixed table-layout algorithm is faster because horizontal layout depends on table width, column widths, borders, and cell spacing, not cell contents; it also notes that if `width` is `auto` or unspecified, `fixed` has no effect. [MDN table-layout][ref-table-layout]

## 19. Use Grid `auto-fit` for responsive cards

Prefer auto-fitting Grid over `space-between` plus percentage flex basis for card galleries, because Grid keeps incomplete rows aligned.

```css
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 1.5rem;
}
```

Validation: `repeat()` supports `auto-fit`, `minmax()` defines a size range, and `gap` defines spacing between grid/flex tracks/items. [MDN repeat()][ref-repeat], [MDN minmax()][ref-minmax], [MDN gap][ref-gap]

## 20. Prefer `gap` over margin hacks in Flexbox/Grid

```css
.cluster {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}
```

Validation: `gap` applies to multi-column, flex, and grid layouts and avoids first/last-child margin cleanup. [MDN gap][ref-gap]

## 21. Use logical properties for internationalized layout

```css
.card {
  padding-block: 1rem;
  padding-inline: 1.25rem;
  margin-inline: auto;
}

.overlay {
  position: absolute;
  inset: 0;
}
```

Validation: logical properties map to physical properties depending on writing mode, direction, and text orientation. [MDN logical properties][ref-logical], [MDN margin-inline][ref-margin-inline], [MDN padding-block][ref-padding-block]

## 22. Use `:empty` narrowly

```css
.error-message:empty {
  display: none;
}
```

Validation: `:empty` matches elements with no children; text nodes, including whitespace, make an element non-empty. Scope it to known elements instead of using `:empty` globally. [MDN :empty][ref-empty]

## 23. Use `pointer-events: none` only for pointer hit-testing

```css
button:disabled {
  opacity: 0.5;
  pointer-events: none;
}
```

Validation: `pointer-events: none` affects pointer targeting; MDN notes elements with `pointer-events: none` can still receive focus through sequential keyboard navigation. Prefer the native `disabled` attribute where available. [MDN pointer-events][ref-pointer-events]

## 24. Hide autoplaying unmuted video only as a user stylesheet or controlled policy

```css
video[autoplay]:not([muted]) {
  display: none;
}
```

Validation: the selector is valid CSS because attribute selectors and `:not()` can combine; however, hiding media can affect content access. Use it as a user preference or product policy, not as an invisible surprise. [MDN :not][ref-not]

## 25. Use `@font-face local()` cautiously

```css
@font-face {
  font-family: "ExampleBrand";
  src: url("/fonts/example-brand.woff2") format("woff2");
  font-display: swap;
}
```

Avoid `local()` for strict brand fonts unless you have measured metrics and version risk. A user-installed font with the same name can be stale or metrically different. Use `local()` mainly for system font stacks or when accepting local substitution is intentional.

Validation: MDN documents `local()` in `@font-face src`, including local full font name/PostScript name lookup and notes that user agents may ignore user-installed fonts for security/privacy reasons. `font-display: swap` gives an extremely small block period and an infinite swap period. [MDN @font-face src][ref-font-src], [MDN font-display][ref-font-display]

## 26. Use fluid type with `clamp()` instead of unbounded viewport math

```css
h1 {
  font-size: clamp(1.75rem, 1rem + 3vw, 3rem);
}
```

Validation: `clamp(min, preferred, max)` clamps a value between lower and upper bounds; it is a better default than raw `calc(1vw + 1vh + ...)` because it includes floor and ceiling values. [MDN clamp()][ref-clamp]

## 27. Use `@supports` for layout-changing enhancements

```css
.card {
  position: relative;
}

@supports (anchor-name: --tip) {
  .trigger {
    anchor-name: --tip;
  }

  .tooltip {
    position-anchor: --tip;
    position-area: top;
  }
}
```

Validation: `@supports` tests whether a browser supports a CSS declaration before applying a block. [MDN @supports][ref-supports]

---

# Modern CSS support buckets

## Baseline Widely available / normal production CSS for current evergreen targets

Treat these as normal production CSS for current evergreen targets, while still testing your project’s real browser floor.

### `:has()`

Use `:has()` to style an element based on its descendants or following siblings.

```css
.card:has(> img) {
  grid-template-columns: 8rem 1fr;
}

.field:has(input:focus-visible) {
  outline: 2px solid currentColor;
}
```

Validation: MDN marks `:has()` Baseline Widely available and describes it as matching an element if any relative selector passed as an argument matches when anchored against that element. MDN also notes performance considerations for broad `:has()` usage, so keep selectors scoped. [MDN :has][ref-has]

### Container queries

Use container queries when a component should respond to its parent/container instead of the viewport.

```css
.wrapper {
  container-type: inline-size;
}

.card {
  grid-template-columns: 1fr;
}

@container (width > 400px) {
  .card {
    grid-template-columns: auto 1fr;
  }
}
```

Validation: MDN marks container queries Baseline Widely available and describes them as applying styles to descendants based on a container’s size or style. [MDN container queries][ref-container-queries], [MDN @container][ref-container-at]

### Native CSS nesting

Use native nesting for readability, but keep `&` explicit when joining selectors or pseudo-classes.

```css
.card {
  padding: 1rem;

  & .title {
    font-weight: 600;
  }

  &:hover {
    background: Canvas;
  }
}
```

Validation: MDN documents that CSS nesting is parsed by the browser, unlike Sass-style preprocessing. Nesting became Baseline Newly available in August 2023 and crossed the 30-month mark in February 2026, so it is now Baseline Widely available and needs no guard on evergreen targets. [MDN CSS nesting][ref-nesting], [Can I use CSS nesting][ref-caniuse-nesting], [web.dev Baseline][ref-webdev-baseline]

### Cascade layers with `@layer`

Use layers to define cascade order across reset/base/components/utilities.

```css
@layer reset, base, components, utilities;

@layer base {
  a { color: LinkText; }
}

@layer utilities {
  .text-red { color: red; }
}
```

Validation: MDN marks `@layer` Baseline Widely available and documents that later layers have higher precedence, allowing lower-specificity selectors in later layers to override higher-specificity selectors in earlier layers. [MDN @layer][ref-layer]

### Subgrid

Use `subgrid` when nested grid items need to align to parent grid tracks.

```css
.cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}

.card {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;
}
```

Validation: MDN marks subgrid Baseline Widely available and documents that subgrid lets a grid item use the parent grid’s tracks. [MDN subgrid][ref-subgrid]

### `color-mix()`

Use `color-mix()` for browser-computed tints, shades, and transparent variants. Prefer a perceptual color space such as `oklab`/`oklch` when design intent depends on perceived color.

```css
.btn {
  background: var(--brand);
}

.btn:hover {
  background: color-mix(in oklab, var(--brand) 85%, black);
}
```

Validation: MDN marks `color-mix()` Baseline Widely available and defines it as mixing two colors in a given color space by a specified amount. [MDN color-mix()][ref-color-mix]

### Logical properties

Use flow-relative properties instead of physical `left/right/top/bottom` where layout should adapt to writing mode.

```css
.box {
  margin-inline: auto;
  padding-block: 1rem;
}
```

Validation: MDN defines logical properties and values as mapping to physical equivalents based on writing mode, direction, and text orientation. [MDN logical properties][ref-logical]

### `clamp()`

Use `clamp()` for fluid sizes with hard limits.

```css
.section {
  padding-block: clamp(2rem, 5vw, 5rem);
}
```

Validation: MDN marks `clamp()` Baseline Widely available and describes its min/preferred/max behavior. [MDN clamp()][ref-clamp]

---

## Baseline Newly available / verify support floor

Treat these as production-ready only when your project’s supported browsers include the required versions.

### `text-wrap`

```css
h1,
h2,
.hero-title {
  text-wrap: balance;
}

.prose p {
  text-wrap: pretty;
}
```

Validation: MDN marks `text-wrap` Baseline 2024 Newly available. `balance` balances line lengths, while `pretty` aims for better typography such as avoiding orphans. MDN cautions that `balance` can be computationally expensive and is best for short blocks/headings. The shorthand status hides per-value differences: MDN flags that some parts of the feature have varying support, and `pretty` lands later and less evenly than `balance`, so treat `pretty` as an enhancement even where `balance` is safe. [MDN text-wrap][ref-text-wrap]

### `light-dark()`

```css
:root {
  color-scheme: light dark;
}

body {
  background: light-dark(#fff, #111);
  color: light-dark(#111, #eee);
}
```

Validation: MDN marks `light-dark()` Baseline 2024 Newly available, since May 2024. It returns one of two colors based on active color scheme, and it requires `color-scheme: light dark` or equivalent opt-in. It crosses the 30-month Widely available threshold around November 2026, so this entry moves buckets then. [MDN light-dark()][ref-light-dark], [web.dev Baseline][ref-webdev-baseline]

### `@scope`

```css
@scope (.card) to (.card__content) {
  img {
    border-radius: 8px;
  }
}
```

Validation: MDN marks `@scope` Baseline 2026 Newly available, since March 2026, and describes it as limiting selectors to specific DOM subtrees without requiring over-specific selectors. [MDN @scope][ref-scope]

### `@starting-style`

```css
.toast {
  transition: opacity 0.3s, translate 0.3s;
  opacity: 1;
  translate: 0 0;
}

@starting-style {
  .toast {
    opacity: 0;
    translate: 0 1rem;
  }
}
```

Validation: MDN marks `@starting-style` Baseline 2024 Newly available and defines it as starting values for elements before their first style update. [MDN @starting-style][ref-starting-style]

### Anchor positioning

```css
.trigger {
  anchor-name: --tip;
}

.tooltip {
  position: fixed;
  position-anchor: --tip;
  position-area: top;
  position-try-fallbacks: flip-block;
}
```

Validation: MDN marks `anchor-name`, `position-area`, and `position-try-fallbacks` Baseline 2026 Newly available, completed by Firefox 147 in January 2026. Newly available is not the same as bug-free here: web-features maintainers debated this feature's entry because of broken fixed-position anchors in Safari, `position-try` edge cases, and popover placement gaps. Use `@supports`, keep a non-anchored fallback, and test the real placements you ship. [MDN anchor positioning][ref-anchor-module], [MDN anchor-name][ref-anchor-name], [MDN position-area][ref-position-area], [MDN position-try-fallbacks][ref-position-try-fallbacks]

### `contrast-color()`

```css
.badge {
  background: var(--brand);
  color: white;
}

@supports (color: contrast-color(red)) {
  .badge {
    color: contrast-color(var(--brand));
  }
}
```

Validation: MDN marks `contrast-color()` Baseline 2026 Newly available. It returns black or white based on the input color, but MDN warns that mid-tone backgrounds can still fail readability/WCAG AA, so test real tokens. [MDN contrast-color()][ref-contrast-color]

### `field-sizing`

```css
textarea,
input {
  field-sizing: content;
}
```

Validation: MDN marks `field-sizing` Baseline 2026 Newly available, since June 2026, and defines it as enabling form controls to fit their content. Early Firefox builds implemented it partially and Firefox 152 beta notes describe filling in full support, so keep min/max sizes and a working fallback rather than assuming identical sizing behavior across the Baseline set. [MDN field-sizing][ref-field-sizing], [web.dev platform update, May 2026][ref-webdev-0526]

### Container style queries

```css
.theme-scope {
  container-name: --theme;
}

@container style(--theme: dark) {
  .card {
    background: #14181f;
    color: #e8ecf2;
  }
}
```

Validation: style queries against a custom property became Baseline Newly available in May 2026 when Firefox 151 completed the set. Only custom properties can be queried; `style()` cannot test arbitrary declared values. [MDN container queries][ref-container-queries], [MDN @container][ref-container-at], [web.dev platform update, May 2026][ref-webdev-0526]

### Name-only container queries

```css
#sidebar {
  container-name: --sidebar;
  container-type: inline-size;
}

/* Match the named container without also writing a size condition. */
@container --sidebar {
  .content {
    padding: 2rem;
  }
}
```

Validation: querying a container by name with no size or style condition became Baseline Newly available in May 2026 with Chrome 148. The rule applies whenever a matching named container exists in the ancestor chain. [MDN @container][ref-container-at], [web.dev platform update, May 2026][ref-webdev-0526]

### `:open`

```css
details:open > summary {
  font-weight: 600;
}

dialog:open {
  border-color: color-mix(in oklab, currentColor 30%, transparent);
}
```

Validation: `:open` became Baseline Newly available in May 2026 with Safari 26.5. It matches elements in an open state, including `details`, `dialog`, and `select` with an open picker, which makes the `[open]` attribute selector unnecessary for those cases. Attribute selectors still work as a fallback below your floor. [MDN :open][ref-open], [web.dev platform update, May 2026][ref-webdev-0526]

### `text-box-trim` and the `text-box` shorthand

```css
h1 {
  /* Trim the space above cap height and below the alphabetic baseline. */
  text-box: trim-both cap alphabetic;
}
```

Validation: MDN browser-compat-data records `text-box-edge` and `text-box-trim` in Chrome 133+, Safari 18.2+, and Firefox 154+. Leading trim removes the half-leading that makes headings look mis-centered inside their box. Browsers without support keep normal leading, so the fallback is the old spacing rather than a broken layout. Check your floor before relying on trimmed metrics for tight vertical rhythm. [MDN text-box][ref-text-box], [MDN text-box-trim][ref-text-box-trim], [MDN text-box-edge][ref-text-box-edge]

---

## Limited availability / progressive enhancement only

Ship a working default first. Add these behind `@supports` or feature detection.

### `accent-color`

```css
:root {
  accent-color: rebeccapurple;
}
```

Validation: MDN marks `accent-color` Limited availability. It sets the accent color for some user-interface controls, but browser/element behavior varies, so do not rely on it as the only way to convey state. [MDN accent-color][ref-accent-color]

### Scroll-driven animations

```css
.reveal {
  opacity: 1;
}

@supports (animation-timeline: view()) {
  .reveal {
    animation: fade-in linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 40%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .reveal {
    animation: none;
  }
}
```

Validation: MDN’s scroll-driven animation module documents scroll progress and view progress timelines; `animation-timeline` is marked Limited availability. Support is wider than it used to be: Safari 26 shipped scroll-driven animations, leaving Firefox as the remaining holdout, and the feature is an Interop 2026 focus area. It is still not Baseline, so provide static content by default and honor reduced motion. [MDN scroll-driven animations][ref-scroll-driven], [MDN animation-timeline][ref-animation-timeline], [WebKit scroll-driven animations][ref-webkit-sda], [Interop 2026 CSS focus areas][ref-interop-2026]

### `interpolate-size` and `calc-size()`

```css
@supports (interpolate-size: allow-keywords) {
  :root {
    interpolate-size: allow-keywords;
  }

  .details {
    transition: block-size 0.3s ease;
    block-size: 0;
    overflow: hidden;
  }

  .details.is-open {
    block-size: auto;
  }
}
```

Validation: MDN marks `interpolate-size` and `calc-size()` Limited availability/experimental. Chrome’s developer documentation describes Chrome 129 support and recommends progressive enhancement. Do not treat intrinsic-size interpolation as Baseline yet. [MDN interpolate-size][ref-interpolate-size], [MDN calc-size][ref-calc-size], [Chrome interpolate-size][ref-chrome-interpolate]

### `transition-behavior: allow-discrete`

```css
.dialog {
  transition:
    opacity 0.2s ease,
    display 0.2s allow-discrete;
  transition-behavior: allow-discrete;
}
```

Validation: MDN marks `transition-behavior` Baseline 2024 Newly available and defines `allow-discrete` as starting transitions for discrete animation-type properties. It is not a replacement for `interpolate-size` when the problem is animating to/from intrinsic sizes. [MDN transition-behavior][ref-transition-behavior]

### Typed `attr()`

```css
.columns {
  column-count: 2;
}

@supports (column-count: attr(data-cols type(<number>), 2)) {
  .columns {
    column-count: attr(data-cols type(<number>), 2);
  }
}
```

Validation: `attr()` outside the `content` property is not Baseline. The typed form reads an attribute as a real CSS type with a fallback value, and it currently ships in Chromium while remaining an Interop 2026 focus area. Declare the plain value first and gate the typed version. [MDN attr()][ref-attr], [Interop 2026 CSS focus areas][ref-interop-2026]

### Customizable `<select>`

```css
/* Native select stays intact for every browser that ignores these rules. */
select {
  font: inherit;
}

@supports (appearance: base-select) {
  select,
  ::picker(select) {
    appearance: base-select;
  }

  ::picker(select) {
    border: 1px solid CanvasText;
    border-radius: 0.5rem;
  }
}
```

Validation: `appearance: base-select` and the `::picker(select)` pseudo-element opt a select into a stylable rendering while keeping native semantics and keyboard behavior. It ships in Chromium from Chrome 135, with listbox support following in Chrome 145, and is not Baseline. Never rebuild a select out of divs to get the styling; gate the opt-in and let other browsers keep the platform control. [MDN appearance][ref-appearance], [MDN ::picker()][ref-picker]

### `shape()` for `clip-path`

```css
.blob {
  clip-path: polygon(0 0, 100% 0, 100% 80%, 0 100%);
}

@supports (clip-path: shape(from 0 0, line to 100% 0)) {
  .blob {
    clip-path: shape(
      from 0 0,
      line to 100% 0,
      curve to 100% 80% with 60% 40%,
      line to 0 100%,
      close
    );
  }
}
```

Validation: `shape()` describes a clip path with a path-like command list that accepts CSS units, `calc()`, and custom properties, which `path()` does not. It is an Interop 2026 focus area and is not Baseline, so keep a `polygon()` fallback. [MDN shape()][ref-shape], [Interop 2026 CSS focus areas][ref-interop-2026]

### `corner-shape`

```css
.card {
  border-radius: 1.5rem;
}

@supports (corner-shape: squircle) {
  .card {
    corner-shape: squircle;
  }
}
```

Validation: `corner-shape` changes how `border-radius` corners are drawn, including superellipse and squircle curves. It shipped in Chrome 139 and is not Baseline. Corners fall back to normal rounding, so this is a safe enhancement. [MDN corner-shape][ref-corner-shape]

### Media state pseudo-classes

```css
video:paused::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgb(0 0 0 / 0.35);
}

video:buffering {
  cursor: progress;
}
```

Validation: `:playing`, `:paused`, `:muted`, `:volume-locked`, `:buffering`, `:seeking`, and `:stalled` match media element state without a JavaScript event listener. They are an Interop 2026 focus area rather than Baseline, so drive any state your UI depends on from script and use these for polish. [MDN :playing][ref-playing], [MDN :buffering][ref-buffering], [Interop 2026 CSS focus areas][ref-interop-2026]

---


# More cool modern CSS tricks — validated additions

These additions are meant to sit beside the original patterns. The same rule applies: ship a boring, working fallback first, then enhance only where your browser floor supports the feature.

## 28. Animate real custom properties with `@property`

Unregistered custom properties animate as untyped token strings. Register a property when you want the browser to understand its type, interpolate it, validate it, and give it an initial value.

```css
@property --angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.spinner {
  inline-size: 3rem;
  aspect-ratio: 1;
  border-radius: 50%;
  background: conic-gradient(from var(--angle), currentColor 0 25%, transparent 0);
  animation: spin 1s linear infinite;
}

@keyframes spin {
  to { --angle: 1turn; }
}
```

Validation: MDN marks `@property` as Baseline 2024 Newly available and describes it as a way to explicitly define CSS custom properties, including syntax, inheritance, and initial values. Use computationally independent `initial-value`s such as `0deg`, `10px`, or a named color. [MDN @property][ref-property]

## 29. Make component typography respond to the container with `cqi`

Viewport units make every copy of a component scale the same way. Container query units let each copy scale to its own container.

```css
.article-card-list {
  container-type: inline-size;
}

.article-card h2 {
  font-size: clamp(1.125rem, 0.85rem + 3cqi, 1.75rem);
}

.article-card {
  padding: clamp(1rem, 4cqi, 2rem);
}
```

Validation: MDN documents container query length units: `cqi` is 1% of the query container's inline size, `cqb` is 1% of its block size, and `cqmin`/`cqmax` use the smaller/larger of those axes. If no eligible query container exists, container query units fall back to the small viewport unit for that axis, so set the container deliberately. [MDN container query units][ref-container-query-units]

## 30. Validate forms after interaction with `:user-valid` and `:user-invalid`

Use the user-action pseudo-classes to avoid yelling at users before they have typed anything.

```css
.field {
  display: grid;
  gap: 0.35rem;
}

.field:has(input:user-invalid) {
  color: #b42318;
}

input:user-invalid {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

input:user-valid {
  outline: 2px solid color-mix(in oklab, green 70%, currentColor);
  outline-offset: 2px;
}
```

Validation: MDN marks both `:user-valid` and `:user-invalid` as Baseline Widely available since November 2023. `:user-valid` matches a validated element only after user interaction, while `:user-invalid` represents validated form elements that fail their constraints after interaction. [MDN :user-valid][ref-user-valid], [MDN :user-invalid][ref-user-invalid]

## 31. Style popovers by open state instead of toggling classes

For HTML popovers, use `:popover-open` for the visible state and `::backdrop` for modal-style dimming when the element is placed in the top layer.

```css
[popover] {
  max-inline-size: min(32rem, calc(100vw - 2rem));
  padding: 1rem;
  border: 1px solid color-mix(in oklab, currentColor 25%, transparent);
  border-radius: 0.75rem;
  box-shadow: 0 1rem 3rem rgb(0 0 0 / 0.2);
}

[popover]:popover-open {
  display: grid;
  gap: 0.75rem;
}

[popover]::backdrop {
  background: rgb(0 0 0 / 0.35);
}
```

Validation: MDN marks `:popover-open` as Baseline 2024 Newly available and defines it as matching a popover element in the showing state. MDN marks `::backdrop` as Baseline Widely available, with some support caveats, and defines it as the box rendered beneath top-layer elements. [MDN :popover-open][ref-popover-open], [MDN ::backdrop][ref-backdrop]

## 32. Animate top-layer entrances carefully

Top-layer UI such as popovers and dialogs can combine `@starting-style`, discrete transitions, and `overlay` for smoother open/close behavior. Keep this behind feature checks because `overlay` is still limited.

```css
.toast[popover] {
  opacity: 0;
  translate: 0 0.75rem;
  transition:
    opacity 180ms ease,
    translate 180ms ease;
}

.toast[popover]:popover-open {
  opacity: 1;
  translate: 0 0;
}

@starting-style {
  .toast[popover]:popover-open {
    opacity: 0;
    translate: 0 0.75rem;
  }
}

@supports (transition-behavior: allow-discrete) and (overlay: auto) {
  .toast[popover] {
    transition:
      opacity 180ms ease,
      translate 180ms ease,
      overlay 180ms ease allow-discrete,
      display 180ms ease allow-discrete;
  }
}
```

Validation: `@starting-style` is already covered above as Baseline 2024 Newly available. MDN marks `overlay` as Limited availability and experimental; it is only relevant in `transition-property` when `transition-behavior: allow-discrete` is set. Keep the non-animated open/closed state correct without it. [MDN overlay][ref-overlay], [MDN transition-behavior][ref-transition-behavior], [MDN @starting-style][ref-starting-style]

## 33. Reserve scrollbar space with `scrollbar-gutter`

Prevent content from shifting sideways when a page or pane crosses the overflow threshold.

```css
html {
  scrollbar-gutter: stable;
}

.panel {
  max-block-size: 24rem;
  overflow: auto;
  scrollbar-gutter: stable both-edges;
}
```

Validation: MDN marks `scrollbar-gutter` as Baseline 2024 Newly available and describes it as reserving scrollbar space to prevent unwanted layout changes as content grows. [MDN scrollbar-gutter][ref-scrollbar-gutter]

## 34. Skip offscreen rendering with 

…(truncated)
