Styling

CSS has hundreds of properties, and a browser silently ignores a typo in any of them. In chimera a style is a Luwu table whose values Luwu's type function validators check during analysis: padding = "1rx" is a type error, and dispaly = "flex" gets a "did you mean". Styles can also read theme tokens, and then they follow the reader's theme with no extra CSS.

One element

style sets an element's inline style:

Back up your saves before updating.

const note = Paragraph("Back up your saves before updating.")
    :style({
        padding = "0.75rem 1rem",
        background = token("surface"),
        border_left = `4px solid {token("accent")}`,
        border_radius = token("radius"),
    })

Keys are CSS property names with underscores instead of dashes. Keyword properties like display only accept their real values, while lengths also take plain numbers like margin = 0. Vendor prefixes start with webkit_ or moz_, and custom properties go in brackets: ["--gap"] = "1rem".

Theme tokens

token("accent") stands for var(--chimera-accent), the current theme's accent color. When the reader switches themes, every style that uses it changes with them. These are the tokens every theme sets:

background  surface  text  muted  border
primary  primary_text  accent
radius  spacing  font  mono_font  shadow
syntax_keyword  syntax_string  syntax_comment  ...  syntax_error

token("radius"):times(1.5) scales a length token, and token("primary"):mix(token("background"), 20) blends 20% of one color token into another.

Colors

Tinted

const swatch = Paragraph("Tinted")
    :style({
        padding = "0.5rem 1rem",
        color = Color.named("white"),
        background = Color.hex("#3b5bdb"):mix(Color.named("black"), 0.25),
        border_radius = token("radius"):times(2),
    })

Color.hex checks its literal while you type, and Color.named takes any CSS color name. Colors also convert to and from vectors, packed numbers, buffers and ANSI codes.

Inside one element

style_inside styles the matching elements inside one element and leaves the rest of the page alone:

const credits = Footer({ Small("Art by Nyla."), Link("More art", "#") })
    :row()
    :style_inside(Link, { color = token("muted") })

Every element of a kind

style_every on a Document or a Site styles everything that matches an element class or a CSS selector. These rules come after the theme's and win over them:

site
    :style_every(Button, { border_radius = "999px" })
    :style_every(Card, { padding = "2rem" })
    :style_every(".hero h1", { font_size = "3rem" })

Rules and stylesheets

A Rule pairs a selector with a style. For media queries, nest rules inside one:

document:css({
    Rule("nav a", { color = token("text") }),
    Rule("@media (max-width: 600px)", {}, {
        Rule("nav", { flex_direction = "column" }),
    }),
})

document:css(text) also takes plain CSS, and link_stylesheet(href) links a stylesheet file. Going the other way, Rule.parse and Style.parse read CSS back into objects.

Styles that a component always needs belong in the component itself, as Custom components shows.