CSS in Chawan
This document describes CSS features supported by Chawan, as well as its proprietary extensions and deviations from standards.
If you discover a deviation that is not covered by this document, please open a ticket at https://todo.sr.ht/~bptato/chawan.
Standard properties
A list of supported standard properties, with notes on unimplemented values:
- background-color (see color)
- background-image (displays placeholders only)
- border-collapse
- border-*-style, border-*-color, border-*-width (but see borders)
- border-spacing
- bottom
- box-sizing
- caption-side
- clear
- color (hex values and functions
rgb,rgba,hsl,hsla) - content (string, (no-)open/close-quote, counter())
- counter-increment
- counter-reset
- counter-set
- display (
block,inline-block,list-item,table,table-*,flex,inline-flex,flow-root) - flex-basis (but
contentnot supported) - flex-direction
- flex-grow
- flex-shrink
- flex-wrap
- float
- font-size (ignored; only for JS compatibility)
- font-style (
obliqueinterpreted asitalic) - font-weight (numeric properties > 500 interpreted as bold, others as regular)
- height
- left
- list-style-position
- list-style-type (but no custom list styles)
- margin-bottom
- margin-left
- margin-right
- margin-top
- max-height
- max-width
- min-height
- min-width
- opacity (hacky; only works with
opacity: 0) - overflow-x (see below on scrollbars)
- overflow-y (see below on scrollbars)
- padding-bottom
- padding-left
- padding-right
- padding-top
- position (see below for
stickyandfixed) - quotes
- right
- text-align
- text-decoration (
none,underline,overline,line-through) - text-transform
- top
- vertical-align
- visibility
- white-space
- width
- word-break
- z-index
Shorthands:
- all
- margin
- padding
- border, border-style, border-color, border-width (but see borders)
- background (only color and url; other components are skipped)
- list-style (list-style-image is skipped)
- flex
- flex-flow
- overflow
Variables (the var() function) are fully supported.
Values of <length> or <color>
types fully support calc() expressions.
Selectors
All selector types from CSS 2.1 are supported, except for namespaces.
Following standard pseudo-classes are supported:
:first-child, :last-child,
:only-child, :hover, :root,
:nth-child(), :nth-last-child(),
:checked, :focus, :is(),
:not(), :where(), :lang(),
:link, :target, :disabled.
:visited is parsed, but for now it is not matched.
:defined, :host, and :host()
are matched for compatibility; however, custom elements and shadow DOM
are not supported yet.
The standard pseudo-elements ::before,
::after, and ::marker are supported.
::backdrop is parsed for compatibility, but is not
supported yet.
At-rules
Following rules starting with an @ sign are
supported.
@media
The grid, hover,
prefers-color-scheme, scripting,
width, and height media features are fully
supported.
The color, color-index, and
monochrome features are supported, but only consider the
number of supported text colors (which can differ from the number of
colors in Sixel/Kitty images).
@import
Importing to layers is supported.
@import combined with media queries is not yet
supported.
@layer
@layer is fully supported. (I think.)
Proprietary extensions
text-alignaccepts the values-cha-center,-cha-left, and-cha-rightto support the HTML<center>,<div align=left>and<div align=right>elements. (Analogous to-moz-centeretc.)Properties with a
<color>value accept the function-cha-ansi(), mapping to terminal-specific (“ANSI”) colors. The function takes one ofAn 8-bit integer, indicating a color value as set by XTerm’s indexed color feature.
One of the strings “black”, “red”, “green”, “yellow”, “blue”, “magenta”, “cyan”, “white” for an ANSI color, possibly prefixed by the string “bright-” to indicate an aixterm 16-color value.
text-decorationaccepts the keyword-cha-reverse, which sets the reverse video parameter on the text. (This is used by the UA style sheet to highlight text in<code>tags.)text-transformaccepts the keyword-cha-half-width, which has the opposite effect asfull-width.This can be used in user style sheets to compress distracting ruby text:
rt{text-transform: -cha-half-width}. Characters without half-width counterparts are left intact, except hiragana is treated as katakana.The
-cha-colspanand-cha-rowspanproperties have the same effect as thecolspanandrowspanattributes on tables.The
:-cha-first-nodeand:-cha-last-nodepseudo-classes apply to elements that have no preceding/subsequent sibling node that is either an element node or a text node with non-whitespace contents. (Modeled after:-moz-first-nodeand:-moz-last-node.)If
buffer.mark-linksis set, the::-cha-link-markerpseudo-element will be generated on all anchor elements.In hints mode (by default, the
fkey) the markers are implemented by generating::-cha-link-hinton all applicable elements. So you can change the marker background in youruser-style([buffer]section inconfig.toml):::-cha-link-hint { background: gainsboro }The
-cha-content-typemedia feature can be used to filter documents for their content type. For example, you can add@media (-cha-content-type: "text/markdown") { body { width: 80ch } }to your
user-styleto set the body width of all markdown documents to 80 characters. (The string is matched case-insensitively.)
Rendering quirks
These are willful violations of the standard, usually made to better fit the display model inherent to projecting the web to a cell-based screen.
User agent style sheet
The user agent style sheet is a combination of the styles suggested by the HTML standard and a CSS port of w3m’s rendering. In general, faithfulness to w3m is preferred over the standard’s suggestions, unless w3m’s rendering breaks on existing websites.
Link colors differ depending on the terminal’s color scheme.
Sizing and positioning
Layout is performed on a finite canvas of coordinates represented by a 32-bit fixed-point number with 6 bits of precision. After layout, these positions are divided by the cell width and/or height, with the fractional part truncated. (This is subject to change.)
In case of Kitty images, the fractional part is preserved, and is used as an in-cell offset.
The lengths 1em and 1ch compute to the cell
height and cell width respectively.
In outer inline boxes (inline-block,
inline-flex) and list-item boxes, margins and
padding that are smaller than one cell (on the respective axis) are
ignored. This does not apply to blockified inline boxes.
When calculating clip boxes (overflow: hidden or
clip), the clip box’s offset is floored, and its size is
ceiled to the nearest cell’s boundaries. This means that “width: 1px;
overflow: hidden” will still display the first character of a text
box.
Scroll bars
Chawan does not have scroll bars, as they would complicate on-page navigation and would not work in dump mode. Instead, the “overflow-x/y” properties are handled as follows.
- If
overflowisautoorscroll, and the intrinsic minimum size of the box is greater than its specified size, then the former overrides the latter. - Content that spills out of a scroll container on the X axis is displayed, while content that spills out of a scroll container on the Y axis is clipped.
position: fixed,
position: sticky
To keep the document model static, these do not change their position based on the viewport’s scroll status. Instead:
position: stickyis treated asposition: static, except it also behaves as an absolute position container.position: fixedis placed at the bottom of the document.
Right now, position: fixed is always positioned at the
bottom of the root element’s margin box. This breaks on pages that
overflow it (e.g. by setting height: 100% on the root
element), so it will be moved to the bottom of its overflow box in the
future.
Color correction
Some authors only specify one of the foreground or the background
color, assuming a black-on-white canvas. The
display.minimum-contrast option adjusts the foreground
color so that text remains readable even if the terminal background does
not match this expectation. (The exact algorithm is unspecified and
subject to change.)
To avoid breaking spoiler mechanisms that rely on “black on black” text, color correction is not invoked on cells that have an RGB color (typically specified by the author.)
Borders
CSS borders are difficult to accurately display on a cell-based display. So while the functionality exists, it has some limitations:
- On tables, borders are always collapsed, even when
border-collapseis set toseparate. - With
border-collapse: separate, the spacing between cells is the largest ofborder-spacingtimes two and the cell width. border-*-widthis interpreted as a binary value: a width of 0 results in no border, while any other width results in a border of a single type. If the width is smaller than one cell (in the respective direction), the rest is subtracted from the margin (if there is any margin).box-sizing: border-boxactually sets the padding box size, so that borders rounded up to the cell size do not accidentally take all space from the actual content. (That in turn would cause problems if a child box setoverflow: hidden, etc.)