What's New in CSS 2026

CSS features shipping in 2026. Mixins, cross-document view transitions, gap decorations, reading flow, and more browser interop improvements.

Browsers are also fixing cross-browser inconsistencies in 2026 through the Interop program. See what's being fixed →

CSS Mixins (@mixin)

WorkflowChrome 146 (expected)

Define reusable blocks of declarations with @mixin --name { ... } and apply them with @apply --name. Like Sass mixins but native, with support for parameters and conditional logic.

@mixin --center {
  display: flex;
  align-items: center;
  justify-content: center;
}

.card { @apply --center; }

Cross-Document View Transitions

AnimationChrome 134, Safari 18.2

View transitions now work across full page navigations (MPA), not just SPA. Use @view-transition { navigation: auto } to animate between pages served by the same origin.

@view-transition {
  navigation: auto;
}

::view-transition-old(root) {
  animation: fade-out 0.3s;
}
::view-transition-new(root) {
  animation: fade-in 0.3s;
}

CSS Gap Decorations

LayoutChrome 147 (expected)

Style the gaps in grid and flex layouts with column-rule-like properties for both axes. Draw lines, dashes, or gradients between grid tracks without extra DOM elements.

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 20px;
  column-rule: 1px solid #ccc;
  row-rule: 1px dashed #eee;
}

Reading Flow

LayoutChrome 137

Control the keyboard tab and screen reader navigation order of flex and grid children with reading-flow: flex-visual or grid-rows. No need for manual tabindex reordering.

.flex-nav {
  display: flex;
  flex-direction: row-reverse;
  reading-flow: flex-visual;
}

.grid-layout {
  display: grid;
  reading-flow: grid-rows;
}

Scroll-Driven Animations Interop

AnimationBaseline 2026 (expected)

animation-timeline: scroll() and view() reach cross-browser baseline. Firefox and Safari ship full support, making scroll-driven animations production-ready without prefixes.

.reveal {
  animation: fade-in linear;
  animation-timeline: view();
  animation-range: entry 0% entry 100%;
}

@keyframes fade-in {
  from { opacity: 0; transform: translateY(20px); }
  to { opacity: 1; transform: translateY(0); }
}

CSS Grid Lanes

LayoutSafari 26.4. Chrome, Edge, and Firefox behind a flag.

Native masonry via display: grid-lanes. Define columns for a waterfall, or rows for a brick layout. Items pack into the lane with the most room. Replaces Masonry.js and the old display: masonry / grid-template-rows: masonry prototypes.

.gallery {
  display: grid;
  display: grid-lanes;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 16px;
}

Relative Color Syntax Interop

ColorBaseline 2026

oklch(from var(--base) ...) and color-mix() reach full cross-browser baseline. All major engines now support relative color manipulation natively.

:root { --brand: oklch(65% 0.25 260); }

.lighter {
  color: oklch(from var(--brand) calc(l + 0.2) c h);
}
.muted {
  color: oklch(from var(--brand) l calc(c * 0.5) h);
}

@starting-style Interop

AnimationBaseline 2026

@starting-style reaches cross-browser baseline, enabling entry animations from display: none without JavaScript timing hacks in all major browsers.

dialog[open] {
  opacity: 1;
  transform: scale(1);
  transition: opacity 0.3s, transform 0.3s;
}

@starting-style {
  dialog[open] {
    opacity: 0;
    transform: scale(0.95);
  }
}

CSS Custom Highlight API Improvements

SelectorChrome 105, Firefox 140, Safari 17.2, Edge 105

The Highlight API gains new features for custom text highlighting. Create spell-check indicators, search highlights, and collaborative editing marks with pure CSS styling.

/* JavaScript: create ranges */
const range = new Range();
range.setStart(node, 0);
range.setEnd(node, 5);
CSS.highlights.set('search', new Highlight(range));

/* CSS: style the highlight */
::highlight(search) {
  background: oklch(85% 0.15 90);
  color: black;
}

contrast-color() Function

ColorChrome 147, Firefox 146, Safari 26, Edge 147. Baseline 2026.

Automatically pick a readable text color based on background luminance. contrast-color(bg) returns whichever of black or white meets WCAG AA contrast against the given color. No manual checking needed.

.badge {
  background: var(--bg);
  color: contrast-color(var(--bg));
}

/* vs: manually hardcoding per variant */
.badge-blue { color: white; }
.badge-yellow { color: black; }

Scoped Styles (@scope)

SelectorChrome 143, Firefox 146, Safari 26.4, Edge 143. Baseline 2026.

@scope is Baseline Newly available. Proximity-based styling with upper and lower bounds is a practical alternative to BEM and CSS Modules.

@scope (.card) to (.card-content) {
  :scope {
    border: 1px solid #ddd;
    border-radius: 12px;
  }
  h2 { font-size: 1.2rem; }
  p  { color: gray; }
}

field-sizing

LayoutChrome 123, Firefox 152, Safari 26.2, Edge 123. Baseline 2026.

field-sizing: content makes form fields grow with their contents. A textarea sizes itself to the typed text. No scrollHeight listener, no height reset on every keystroke.

textarea {
  field-sizing: content;
  min-height: 3lh;
}

:open Pseudo-class

SelectorChrome 133, Firefox 136, Safari 26.5, Edge 133. Baseline 2026.

:open matches elements that are currently open. That includes expanded details, visible dialogs, and showing popovers. One selector instead of [open] plus separate popover rules.

details:open {
  border-color: #3b82f6;
}

dialog:open {
  opacity: 1;
}

shape() Function

AnimationChrome 135, Firefox 148, Safari 18.4, Edge 135. Baseline 2026.

Create responsive clip paths with shape(). Coordinates use percentages and CSS units instead of SVG path() values that break on resize. Chrome, Firefox, Safari, and Edge all ship it.

.blob {
  clip-path: shape(
    from 0% 50%,
    curve to 50% 0% with 0% 0%,
    curve to 100% 50% with 100% 0%,
    curve to 50% 100% with 100% 100%,
    curve to 0% 50% with 0% 100%
  );
}

sibling-index() and sibling-count()

AnimationChrome 138, Firefox 154, Safari 26.2, Edge 138. Baseline 2026.

sibling-index() returns an element's position among siblings. sibling-count() returns the total. Both are Baseline Newly available. Staggered delays and equal-width layouts no longer need nth-child index variables.

.card {
  animation-delay: calc(sibling-index() * 80ms);
  opacity: 0;
  animation: fade-in 0.4s forwards;
}

.item {
  flex-basis: calc(100% / sibling-count());
}
ESC