Styling
Every surface starts with the host's stylesheet, which hands it the terminal's look: its colours, its font and the size of its cells (§8). A document that draws with it looks like part of the terminal, and follows the terminal when its theme changes. Any rule of the document's own wins over it.
The host stylesheet
The host's rules lose to every rule in the document, as a browser's default styles do. So they set a starting point, and your CSS decides. On the root they set:
| property | value |
|---|---|
color, background |
the terminal's foreground and background |
font-family, font-size |
the terminal's font, at its size |
line-height |
one cell's height, so 1rlh is one row |
color-scheme |
the terminal's scheme, dark or light |
accent-color |
the terminal's blue |
overflow |
hidden: nothing scrolls unless the document asks (Surfaces) |
body has no margin. The stylesheet also defines custom properties, for a
document to use in its own rules:
| property | holds |
|---|---|
--hotty-fg, --hotty-bg |
the terminal's foreground and background |
--hotty-ansi-0 … --hotty-ansi-15 |
the 16 ANSI colours of the terminal's theme |
--hotty-accent |
the terminal's blue: ansi-12 when the scheme is dark, ansi-4 when light |
--hotty-font |
the terminal's font family, then monospace |
--hotty-cell-w, --hotty-cell-h |
one cell, in CSS pixels |
--hotty-px |
one device pixel, in CSS pixels |
The prefixes --hotty- and, for attributes, data-hotty- belong to the
protocol. Name your own properties otherwise.
The palette
The 16 ANSI colours are the one palette every terminal theme designs for contrast (Appendix B). A document that draws with them reads well in whatever theme the user picks:
.ok { color: var(--hotty-ansi-2); } /* green */
.fail { color: var(--hotty-ansi-1); } /* red */
.muted { color: var(--hotty-ansi-8); } /* bright black, for secondary text */
.card { border: 1px solid var(--hotty-ansi-8);
background: color-mix(in srgb, var(--hotty-bg) 85%, var(--hotty-accent)); }
Form controls take the palette too: fields, buttons, checkboxes, focus
rings, links and selected text. They are drawn in the terminal's colours,
not the engine's, so they look the same on every host. ansi-8 draws
their borders, buttons, placeholders and whatever is disabled.
A document that styles its own controls wins here, as everywhere else.
Light and dark
The host's capabilities say whether the terminal's scheme is dark or
light, in scheme (§4).
The stylesheet sets color-scheme to match, and prefers-color-scheme
follows it. So a document can keep colours of its own for each:
:root { --line: #3c9; }
@media (prefers-color-scheme: light) { :root { --line: #075; } }
When the terminal's theme changes, the host updates the stylesheet and
draws every surface again. A document that draws with the palette follows
on its own, with nothing sent. The program hears caps only if the scheme
itself changed, with the new scheme.
Sizes in cells
--hotty-cell-w and --hotty-cell-h are one cell in CSS pixels, as
cellcss is in the capabilities. With them, a document lines up with the
terminal's grid: a label as wide as 12 cells, or a gap of one row.
.label { width: calc(12 * var(--hotty-cell-w)); }
.rows { display: grid; gap: 1rlh; } /* the root's line-height is one row */
The surface is c by r cells, and that is its viewport
(§5.3). Media queries and viewport units see
that size, so a document can lay itself out for the width it is placed at.
When the terminal's font changes, so does the size of a cell in CSS
pixels. The host lays every document out again with the new
--hotty-cell-*, and sends caps with the new cellcss. A placement
keeps its cells, and one that asked hears fit if its content now needs
other rows (Surfaces).
Fonts
The root's font is the terminal's, at its size, and --hotty-font names
its family. A document can set any other, such as proportional type for
prose. Code and figures that should line up with the cells around it keep
the terminal's font.
body { font-family: sans-serif; }
code, .num { font-family: var(--hotty-font); }
A font of the document's own comes as a resource, which @font-face
names with cid:. It can also come from the network, where the host and
the document both allow it (Images and the network).
@font-face { font-family: Inter; src: url(cid:inter); }
One device pixel
--hotty-px is one device pixel in CSS pixels: 1px divided by the host's
scale (§8). With it, a rule or a border is exactly one device pixel thick
at every zoom, and a box can snap to the screen's pixels:
hr { border: 0; border-top: var(--hotty-px) solid var(--hotty-ansi-8); }
A zoom changes how many device pixels a CSS pixel is, and nothing else
(§5.3). The cell, the root font and the layout stay as they were, as a
page's do in a frame under a browser's zoom. The host draws the document
again, sharp, with --hotty-px at its new value.
| what changes | what the host does | the program hears |
|---|---|---|
| a zoom, or a display of another density | draws every surface again at the new scale, layout kept | nothing |
| the terminal's font | lays every document out again for the new cell | caps with cellcss |
| the terminal's theme | updates the stylesheet, draws every surface again | caps with scheme, if the scheme changed |
scale in the capabilities is a hint for images: device pixels per CSS
pixel when the host answered. An image with that many pixels for each CSS
pixel it covers is sharp then, though a zoom may change it later without
a word.
CSS the host reads
Some CSS tells the host how to behave, not only how to draw:
| property | what the host does with it |
|---|---|
overflow |
in a document that scrolls, auto and scroll make an element scroll (Surfaces) |
overscroll-behavior |
stops a gesture going on outward, to the terminal |
scrollbar-width, scrollbar-color, scrollbar-gutter |
style the host's scrollbars |
cursor |
sets the pointer over the element, as in a browser |
user-select |
none keeps the user from starting a selection there |
touch-action |
on an element that opts in to drags, decides whether a finger drags it or scrolls (Input) |
What CSS a host handles
The corpus holds the HTML and CSS a surface is expected to handle. Each of its pages tests a part of it, and reads at 80×24 cells:
- cards and typography: flexbox, headings, lists, quotes and
pre; - grids and tables:
grid-template-areas,fr,minmax(),colspanandborder-collapse; - form controls: text fields, checkboxes, radio buttons, ranges, selects, progress and meters;
- effects: shadows, gradients, transforms,
opacity,clip-pathandfilter; - Unicode: CJK, emoji, right-to-left text and combining marks;
- selectors and values:
:has(),:is(), nesting,@layer,calc(),clamp(),aspect-ratioand container queries; - overflow:
text-overflow,position: stickyand absolute positioning; - SVG and images, with icons drawn in
currentColor.
Not every host is a browser, so hosts judge their rendering of these pages against a browser's. Pixels inside a surface may differ between hosts, as text does between fonts. The cells it covers may not (§5.3).
A surface is not a page, and some CSS stops at its edge (Security):
- nothing draws outside the rectangle,
position: fixedincluded; url(),@importand@font-faceload only what the program sent,data:URLs, and what the network policy allows (Images and the network);- nothing scrolls unless the document asks (Surfaces).