:root {
--surface-primary: #eee;
--surface-secondary: #ccc;
--text-primary: #111;
--text-secondary: #333;
/* expand to >1K LOC… */
}
:root {
color-scheme: light dark;
/* vars: light values (>1K LOC) */
}
@media (prefers-color-scheme: dark) {
:root {
--surface-primary: #111;
--surface-secondary: #333;
--text-primary: #eee;
--text-secondary: #ccc;
/* expand to >1K LOC… */
}
}
:root {
color-scheme: light dark;
/* vars: light values (>1K LOC) */
}
@media (prefers-color-scheme: dark) {
:root {
/* vars: dark values (>1K LOC) */
}
}
[data-theme="dark"] {
color-scheme: dark; /* lock UA styles to dark */
/* vars: dark values (>1K LOC repeated!) */
}
:root,
[data-theme="light"] {
color-scheme: light dark;
/* vars: light values (>1K LOC) */
}
[data-theme="light"] {
color-scheme: light; /* lock UA styles to light */
}
@media (prefers-color-scheme: dark) {
:root {
/* vars: dark values (>1K LOC) */
}
}
[data-theme="dark"] {
color-scheme: dark; /* lock UA styles to dark */
/* vars: dark values (>1K LOC repeated!) */
}
light-dark()The new light-dark() function lets you define both values in one line:
light-dark(<lightValue>, <darkValue>)
url(), gradients:root {
color-scheme: light dark;
--surface-primary: light-dark(#eee, #111);
--surface-secondary: light-dark(#ccc, #333);
--text-primary: light-dark(#111, #eee);
--text-secondary: light-dark(#333, #ccc);
/* expand to >1K LOC… */
}
:root {
color-scheme: light dark;
--surface-primary: light-dark(#eee, #111);
--surface-secondary: light-dark(#ccc, #333);
--text-primary: light-dark(#111, #eee);
--text-secondary: light-dark(#333, #ccc);
/* expand to >1K LOC… */
}
[data-theme="light"] {
color-scheme: light; /* forces <lightValue> */
}
[data-theme="dark"] {
color-scheme: dark; /* forces <darkValue> */
}
CanIUse Baseline 2024, supported in major browsers, covering 87.24% of global usage.
@import "tailwindcss"; /* v4 */
@theme {
--surface-primary: light-dark(#eee, #111);
--surface-secondary: light-dark(#ccc, #333);
--text-primary: light-dark(#111, #eee);
--text-secondary: light-dark(#333, #ccc);
}
<!-- media query -->
<html class="scheme-light-dark">
<!-- override -->
<html class="scheme-light">
<html class="scheme-dark">
$red: #f00;
.button.red {
background: $red;
}
.button.red:hover {
background: lighten($red, 20%);
}
:root {
--red: #f00;
}
.button.red {
background: var(--red);
}
.button.red:hover {
background: lighten(var(--red), 20%);
}
:root {
--red: #f00;
}
.button.red {
background: var(--red);
}
.button.red:hover {
background: rgb(from var(--red) r, g, b, 0.8);
}
Existing color functions don’t need commas.
rgb(25, 25, 25)
rgb(25 25 25)
hsl(120, 50, 50)
hsl(120 50 50)
Existing color functions implicitly handle alpha.
rgb(25, 25, 25, 0.8)
rgb(25 25 25 / 0.8)
hsl(120, 50, 50, 0.4)
hsl(120 50 50 / 0.4)
from down...rgb(
from var(--red) r, g, b, alpha
)
normal CSS color function,
could be hsl(), oklch(), etc
extracts channel data from any color
any color or color variable,
in any format
output each color channel & alpha,
any channel can be overridden
Reminder: new syntax, identical output
rgb(
from var(--red) r, g, b, alpha
)
rgb(
from var(--red) r g b / alpha
)
:root {
--surface-primary--coolest: rgb(
from var(--surface-primary) r g 255
);
--surface-primary--warmer: rgb(
from light-dark(#eee, #111) calc(r + 150) g b
);
}
:root {
--surface-primary--shadow: hsl(
from var(--surface-primary) h s l / 0.8
);
--surface-primary--shadow-light: rgb(
from var(--surface-primary) r g b / 20%
);
}
:root {
--surface-primary--dark: hsl(
from var(--surface-primary) h s 20
);
--surface-primary--lighten: hsl(
from var(--surface-primary) h s calc(l + 15)
);
}
:root {
--red: #f00;
--red--100: hsl(from var(--red) h s 90);
--red--200: hsl(from var(--red) h s 80);
--red--300: hsl(from var(--red) h s 70);
--red--400: hsl(from var(--red) h s 60);
--red--500: hsl(from var(--red) h s 50);
--red--600: hsl(from var(--red) h s 40);
--red--700: hsl(from var(--red) h s 30);
--red--800: hsl(from var(--red) h s 20);
--red--900: hsl(from var(--red) h s 10);
}
:root {
--start: dodgerblue;
--primary: hsl(
from var(--start) h s l
);
--secondary: hsl(
from var(--start) calc(h + 120) 67 33
);
--tertiary: hsl(
from var(--start) calc(h + 240) 67 33
);
}
@mixin button($color: $blue) {
color: color.scale($color, $lightness: -15%);
border-color: $color;
background: color.change($color, $lightness: 90%);
&:hover {
color: color.scale($color, $lightness: -25%);
border-color: color.scale($color, $lightness: -15%);
background: color.change($color, $lightness: 80%);
}
/* other interactive states, etc */
}
.button.red {
@include button($red);
}
.button.green {
@include button($green);
}
.button.orange {
@include button($orange);
}
.button {
--button-color: var(--blue);
color: hsl(from var(--button-color) h s calc(l - 15));
border-color: var(--button-color);
background: hsl(from var(--button-color) h s 90);
}
.button:hover {
color: hsl(from var(--button-color) h s calc(l - 25));
border-color: hsl(
from var(--button-color) h s calc(l - 15)
);
background: hsl(from var(--button-color) h s 80);
}
.button.green {
--button-color: var(--green);
}
.button.red {
--button-color: var(--red);
}
.button.orange {
--button-color: var(--orange);
}
CanIUse Baseline 2024, supported in major browsers, covering 89.26% of global usage.
color-mix().button {
background: color-mix(
in hsl,
var(--button-color) 80%,
var(--shadow-tint)
);
}
color-mix(
in hsl,
var(--button-color) 80%,
var(--shadow-tint)
);
mix 2 colors together,
like Sass mix()
a color space:srgb, hsl, oklch, etc
the first color,
optional percentage
the second color,
optional percentage
CanIUse Baseline 2024, supported in major browsers, covering 91.53% of global usage.
contrast-color()button {
background: var(--button-color);
color: contrast-color(
var(--button-color)
);
}
Photo by Birger Strahl on Unsplash
Photo by Birger Strahl on Unsplash
black & white…color-mix()button {
background: var(--button-color);
color: color-mix(
in hsl,
contrast-color(
var(--button-color)
) 90%,
var(--button-color) 10%
);
}
CanIUse Baseline 2024, supported in major browsers, covering 67.46% of global usage.
light-dark()color-mix()contrast-color()jdsteinbach