Skip to content
@erikakers/slate

The four theme blocks, live

Four blocks, three reader states

A reader is in one of three states, not two: no preference stamped, in which case the operating system decides; an explicit light choice; an explicit dark choice. Serving all three takes four blocks, and the site's theme toggle stamps data-theme on <html> to reach the last two.

:root                                       /* the complete LIGHT palette */
@media (prefers-color-scheme: dark) :root   /* OS dark, for the un-stamped case */
:root[data-theme='light']                   /* explicit light, over OS dark */
:root[data-theme='dark']                    /* explicit dark, over OS light */

Order and specificity both carry weight. A media query adds no specificity, so OS dark beats the base on source order alone and has to be written after it. Both stamped blocks carry an attribute, so they beat OS dark whatever the order, which is what lets a reader's choice win back over the operating system. The base block stays at plain :root: anything that outranks it would take a consumer's own :root declaration out of the cascade for no gain.

The demo

The same content under all four blocks, drawn from the measured palette. Pick a reader state; the panel whose block the cascade resolves to carries the ring. To see the override, pick the explicit state your operating system disagrees with: the stamped panel is active and the OS panel is not.

Reader state
:root

Unstamped, so the operating system decides. The base block is the complete light palette.

Text on bgControl
@media (prefers-color-scheme: dark) :root

OS dark, for the unstamped case. A media query adds no specificity, so it beats the base on source order alone.

Text on bgControl
:root[data-theme='light']

Explicit light. Carries an attribute, so it outranks OS dark whatever the order: the reader wins back over the operating system.

Text on bgControl
:root[data-theme='dark']

Explicit dark, over OS light. The mirror of the panel above: an explicit stamped state always beats the OS preference when they conflict.

Text on bgControl