Conditions
The stylesheet holds every visual choice. This page covers
how those choices vary: by environment and by what the surface is for.
There is no view-selection engine — no scoring,
no extends, no “pick one profile” step. Variation is exactly what the CSS
cascade already does: rules guarded by conditions, resolved by layers,
specificity, and source order.
Environment conditions — real @media
Anything the rendering environment can answer is a native media query, so a bare file adapts in any browser with zero tooling:
| Axis | Spelling |
|---|---|
| medium | @media screen, @media print |
| viewport width / height | (min-width: …), (max-width: …) |
| orientation | (orientation: portrait | landscape) |
| color capability | (monochrome), (color) — e-ink targets |
| pointer / hover | (pointer: coarse | fine), (hover: hover | none) |
| pixel density | (min-resolution: …) |
| color scheme | light-dark() values + color-scheme (see Theming) |
The engine evaluates the same enumerated feature set in JS wherever a live browser cascade isn’t available — the paginator, print materialization, EPUB encoding, and preview emulation: the app can enumerate every condition a sheet mentions and render it under a forced environment (a monochrome e-reader, a narrow phone, the printed page), using the same transform the EPUB encoder uses — so preview-on-device is what the export gets.
App conditions — data-spub-* guards
What the environment can’t answer — what the surface is for, which device profile is targeted, which export is running — is applied by the app (or the export pipeline) as attribute tokens on the document root, and tested by ordinary attribute selectors:
html[data-spub-intent~="edit"] main { --spub-editor-current-line: highlight; }
html[data-spub-device~="ereader"] main { font-family: serif; }
html[data-spub-package~="epub"] main { max-width: none; }
| Axis | Attribute | Tokens |
|---|---|---|
| intent | data-spub-intent |
write · edit · read · skim · annotate · proof · cover · snippet |
| device | data-spub-device |
the class vocabulary phone · tablet · desktop · ereader and open device-profile ids (kindle-paperwhite) in one list — either matches |
| export syntax | data-spub-syntax |
syntax ids, during an export render pass |
| package | data-spub-package |
package ids (epub), during package encoding |
| scheme | data-spub-scheme |
light | dark — the app’s explicit override |
The attributes are runtime state, never serialized into a file. In a bare browser they are absent, every guard is inert, and the unguarded rules apply — so a bare file is the read-on-screen posture, by construction. A guard adds attribute specificity, so a rule stating more conditions beats one stating fewer — the browser enforces what the old scoring engine used to compute.
The reader’s own layer
The app composes two more layers around every document (spec §Layers): the
user’s Default Style (sp-user) fills in under the document’s
sheet — the document’s stated choices win, the user’s cover the gaps — and
flipping “always use my style” moves it above (sp-tweaks), together with
any per-surface runtime tweaks. The app may hold several Default Styles scoped
by surface (a reading default, an editing default), all composing into this
layer. Both are app state; a serialized document never carries them.
What replaced the old model
config.views, use clauses, extends/abstract, the selection scorer,
and the layout patch cascade are gone (pre-release — no back-compat). Their
successors: guards + media queries (conditions), @layer order
(inheritance), and --spub-* settings (the non-CSS knobs).
The old theme group dissolved too: light/dark is light-dark() +
color-scheme (see Styling — Theming). Named alternative
stylings (“Looks”) were also part of this rework but have been removed —
alternative tastes belong to the reader’s own layer above, not the document.