Settings
Standard CSS carries most of a document’s appearance. What it can’t express —
how content flows (pages vs scroll), where the app’s panes sit, what page
furniture prints, what the editor does — rides the same
stylesheet as namespaced custom properties. They
cascade, condition, and layer exactly like every other declaration (put one
inside @media print, inside a guard — it just works), and a
bare browser simply ignores them.
Declare them on the document surface (main), or under any condition:
main { --spub-flow: continuous; --spub-outline: right; }
@media print { main { --spub-flow: paged; --spub-numbering: on; --spub-numbering-format: "{n}."; } }
html[data-spub-intent~="edit"] main { --spub-editor-current-line: highlight; }
Renderers resolve them through the engine’s cascade (resolveSettings) — the
same result the browser would compute — and read them as one typed Settings
object. Unknown values degrade to the default (warn, never fail).
The vocabulary
Pagination and flow — whether one-column content scrolls continuously or is split into pages. Multiple columns use a viewport-height horizontal flow:
| Property | Values (default first) |
|---|---|
--spub-layout-justify-content |
space-evenly · start · center · end · space-between · space-around · stretch — placement of the canvas and visible in-layout Outline columns in the workspace |
--spub-flow |
continuous · paged — UI labels: Multi column only · Always |
--spub-flow-columns |
auto · 1 · 2 · 3 · 4 · 5 · 6 — text columns per viewport (auto fits as many as the reading width allows) |
--spub-column-width |
length in rem · px · pt · em · % · words, default 34rem — preferred text-column width; words uses an average five-character word |
--spub-grid-gap |
length, default 2rem — the gap between text columns |
--spub-justify-content |
space-evenly · start · center · end · space-between · space-around · stretch — placement of the packed text column or columns in the content grid track |
--spub-canvas-margin |
length in rem · px · pt · em · %, default 3rem — equal horizontal margins for the canvas area |
--spub-outline-justify-content |
stretch · start · center · end — how Outline content aligns in its grid track when it participates in layout |
--spub-scroll-direction |
vertical · horizontal |
--spub-scroll-snap |
auto · none · page |
The workspace is a CSS grid whose content and visible in-layout Outline occupy
separate, gapless tracks. In multi-column reading the canvas track stretches to
the workspace edges, resolving outer layout justification to stretch for that
flow. --spub-canvas-margin becomes padding inside the scrolling
canvas, so the initial and snapped views retain their inset while text travels
to the viewport edge (or beneath an overlay Outline) during horizontal
scrolling. --spub-layout-justify-content distributes the outer canvas
and Outline tracks; non-stretch modes pack those tracks to their requested
widths before distributing the remaining workspace. Column width, count, gap,
and justification apply inside the
content track in both continuous and paged reading. auto chooses the greatest
whole number of preferred-width columns (up to the supported maximum) that fit
inside the content track, including their gaps; the packed column block is then
placed by --spub-justify-content. With multiple columns, space-between,
space-around, and space-evenly distribute the content track’s remaining
inline space between and, where applicable, around the columns; stretch
expands the columns across that track. Once auto is resolved or an explicit
count is selected, that count is authoritative; columns may shrink below their
preferred width rather than collapsing to fewer columns. auto for snap
resolves to page snapping for paged one-column and multi-column flows, and to
none for continuous one-column flow.
Pagination is resolved after the column count. With one resolved column,
paged (Always) uses vertical pages and continuous (Multi column
only) leaves the document continuous. With two or more resolved columns, both
values use native CSS multi-column fragmentation in a viewport-height container:
the browser fills each column from top to bottom and continues the document
horizontally. Scrolling snaps to each viewport-sized group of columns by
default. CSS columns are anonymous boxes, so the renderer derives only the
horizontal group step from the CSS container width and gap; it never measures
text, lines, or content height. This avoids measured line slices and prevents content from
extending below the viewport or being clipped at an inferred page boundary.
The used horizontal column gap is never smaller than the padded inset, which
keeps neighboring fragments outside that inset at snap points.
The resolved count is recomputed when workspace or Outline geometry changes.
The reading measure, padding, and margins are real CSS on main
(max-width, padding, margin-inline).
Navbar — the outline / index navigator beside the document:
| Property | Values |
|---|---|
--spub-outline |
right · left · top · bottom · overlay · hidden — where the navbar sits (hidden removes it) |
--spub-outline-min-size / --spub-outline-max-size |
legacy range lengths |
--spub-outline-width |
auto or length — preferred Outline width; auto uses its intrinsic content width capped by --spub-column-width |
--spub-outline-display |
layout · overlay · spline — the top-menu Outline button toggles every mode; spline shows division numbers or dots until expanded |
--spub-outline-font-size / --spub-outline-font-family |
outline typography; unset / inherit follows the script |
--spub-outline-text-align |
start · center · end |
--spub-outline-vertical-align |
top · middle · bottom |
--spub-outline-indexes |
show · fold · hide — the derived index groups (Characters, Locations, …) |
Source — the raw document source beside its continuous reading preview:
| Property | Values / meaning |
|---|---|
--spub-source |
right · left — which side holds the Source panel |
--spub-source-width |
length (default 24em) — Source panel width; the workspace divider adjusts it in whole-em steps |
--spub-source-syntax-color |
on · off — color recognized syntax tokens |
--spub-source-line-numbers |
on · off — show a line-number gutter |
--spub-source-wrap-lines |
on · off — wrap long lines instead of scrolling horizontally |
--spub-source-max-line-width |
none or length — cap the readable width of each source line |
Source is a workspace scope, not a modal or a second document representation.
The canvas renders the parsed work exactly as Read does, but resolves to one
continuous scroll column while the source track shows the original text.
Activating Source replaces any visible Outline and resolves the outer workspace
distribution to stretch. The source track reaches both the workspace edge and
the canvas seam; padding belongs inside the panel. Syntax coloring is a viewer
aid and does not alter source bytes. HTML-aware coloring recognizes embedded
JSON and CSS regions as their respective languages.
Progress — the reading-progress indicators:
| Property | Values |
|---|---|
--spub-progress |
none, or a space list of bar · dots · percent · pages · divisions |
--spub-progress-position |
bottom · top |
Page furniture — templates take {n} {pages} {title} {author} {division}:
| Property | Values |
|---|---|
--spub-numbering |
off · on |
--spub-numbering-position |
bottom-center · bottom-left · bottom-right · top-center · top-left · top-right |
--spub-numbering-format |
template string, default "{n}" |
--spub-numbering-from |
integer (earlier pages unnumbered) |
--spub-page-header / --spub-page-footer / --spub-page-watermark |
template strings |
--spub-page-gutter / --spub-page-bleed |
lengths (beyond the native @page size/margins) |
--spub-show-nonprinting |
hide · show — render blocks with behavior.printing: false (notes, boneyard) in paged / print output |
Hiding a whole section is real CSS: section.notes { display: none; }.
Editor behaviour — ignored by read-only renderers:
| Property | Values |
|---|---|
--spub-editor-kind-labels |
off · gutter · active |
--spub-editor-placeholders |
on · off |
--spub-editor-current-line |
off · highlight · typewriter |
--spub-editor-focus |
off · paragraph · division |
--spub-editor-line-numbers |
off · on |
--spub-editor-input |
full · locked · comments-only |
--spub-ribbon |
floating · top · bottom · hidden — the editor toolbar’s placement |
Graceful degradation
A renderer that can’t page falls back to continuous flow and honours the
rest. Settings a surface has no use for (editor knobs in a reader, panes in
an EPUB) are simply unread. The machine-readable catalog — names, types,
enums, defaults — is SETTINGS in @script-pub/format (sheet/settings.ts),
the single source for the format editor’s forms and validation’s warnings.