Standard library · Graphics and games

gui.css

The CSS style engine of the native UI runtime: selectors, the cascade, inheritance, media queries, shorthands, var() and computed values that match Chromium.

import gui.css

This package is the style engine of the native UI runtime. For each element of a page it takes what the web generator writes for it today (its own declarations, the extra ones for hover, focus and active, its element key, classes and id) together with the page's global and media rules, and computes the final value of every property exactly as a browser would. The native window then looks like the web page.

A Sheet starts with the user agent style sheet, the browser defaults that give a heading its size and a paragraph its margins, written after Chromium's own and compared with Chromium property by property. You add rules with AddRule, AddMediaRule or a whole style sheet with AddCss, describe the elements as a vector of Element in document order, and call Compute. Style then gives each element a ComputedStyle: lengths in pixels (percentages stay relative until layout), colours as straight RGBA, keywords as enums, and lists for backgrounds, shadows, transforms and transitions. ToBox turns it into a gui.cssbox style for layout.

Supported: type, class, id and attribute selectors, descendant, child and sibling combinators, :hover, :focus, :focus-visible, :active, the child and type position pseudo-classes, :not(), :is() and :where(); specificity and !important; inheritance with inherit, initial and unset; media queries on size, orientation, colour scheme, reduced motion, hover and pointer; every length unit, calc(), min(), max() and clamp(); colours in every common syntax; gradients, shadows, transforms, transitions, fonts, logical properties for right to left pages, and var() with fallbacks. Grid and table properties are parsed, cascaded and checked: track lists, areas, placements and their shorthands (grid, grid-template, grid-area, grid-row, grid-column), border-collapse, border-spacing, table-layout and caption-side; ToBox hands them to the layout engine. Pseudo-elements, subgrid, animations and container queries are not done.

Things to know

  • An element's own declarations act like a class rule written after the global rules, which is what the web generator emits. Its hover, focus and active declarations act like the same class with that pseudo-class.
  • Elements must come in document order, each after its parent. The page itself has parent -1; an implicit html root above it matches :root.
  • Elements with the same inputs share one computed style. Each distinct declaration string is parsed once.
  • After a pointer move, call HoverChain and pass its result to Restyle: only the elements whose state changed, and their descendants when an inherited value changed, are computed again.
  • Strings returned by the text helpers belong to the caller. The vectors inside a ComputedStyle belong to the sheet.
  • border-image and its longhands, gradient colour hints and calc() stop positions are supported. Gradient stops are resolved when painting with GradientStops, which expands hints and non-sRGB segments in the interpolation colour space the way Chromium does. Colour transitions between non-legacy colours mix in Oklab.
  • Values are applied by keyword id, not by comparing strings, and the cascade passes its large structures by reference: computing all styles of a 202-element page shaped like tools/bench/gui_ui.salam went from about 282 us to about 113 us (minimum of 500 runs, one core, C backend).

Styling a page

A card with a heading and a paragraph. The global rule sets the heading's margins, the user agent sheet gives it its size and weight, and the card's own declarations are converted to a layout style and placed with gui.cssbox.

gui-css-guide-page.salam
import gui.css
import gui.cssbox

func add(els &: Vector<css.Element>, kind: str, parent: int, classes: str, base: str): int:
    mut e := css.NewElement(kind, parent)
    e.classes = classes
    e.base = base
    els.push(e)
    ret els.len() - 1
end

func main:
    mut sheet := css.NewSheet()
    defer sheet.Free()
    _g := sheet.AddRule("*", "box-sizing: border-box")
    _c := sheet.AddRule(".card h2", "margin: 0 0 8px")
    mut els := Vector {} as Vector<css.Element>
    body := add(els, "page", -1, "", "font-family: Vazirmatn, sans-serif; background: #f8fafc")
    card := add(els, "box", body, "card", "padding: 1em; border: 1px solid #e2e8f0; border-radius: 12px; max-width: 30rem")
    title := add(els, "h2", card, "", "color: #0f172a")
    text := add(els, "paragraph", card, "", "line-height: 1.5")
    _n := sheet.Compute(els, css.Env { width = 800.0, height = 600.0 })
    each i in [body, card, title, text]:
        cs := sheet.Style(i)
        println els[i].tag, css.ValueText(cs, "display"), css.ValueText(cs, "font-size"), css.ValueText(cs, "margin-top"), css.ValueText(cs, "padding-top"), css.ValueText(cs, "color")
    end
    mut tree := cssbox.Tree {}
    defer tree.Free()
    mut ids := Vector {} as Vector<int>
    defer ids.free()
    repeat els.len() in i:
        ids.push(tree.AddNode(css.ToBox(sheet.Style(i))))
        if els[i].parent >= 0:
            tree.AddChild(ids[els[i].parent], ids[i])
        end
    end
    tree.Compute(ids[0], cssbox.Definite(800.0), cssbox.Definite(600.0))
    l := tree.Layout(ids[card])
    println "card box", l.x, l.y, l.width, l.height
    repeat els.len() in i:
        mut x := els.ref(i)
        x.Free()
    end
    els.free()
end
Outputbody block 16px 8px 0px rgb(0, 0, 0) div block 16px 0px 16px rgb(0, 0, 0) h2 block 24px 0px 0px rgb(15, 23, 42) p block 16px 16px 0px rgb(0, 0, 0) card box 0 0 480 50

Hover, pressed and media

The button's hover background applies once the pointer is over it, and only the elements on the hover path are computed again. A media condition changes the navigation into a column when the window is narrow. Computing styles for 5,000 elements with 11 distinct styles takes about 10 ms on one desktop core; a hover change restyles four elements in about 0.1 ms. With 5,000 different styles it takes about 100 ms the first time and about 50 ms once the declarations are parsed.

gui-css-guide-states.salam
import gui.css

func main:
    mut sheet := css.NewSheet()
    defer sheet.Free()
    _r := sheet.AddRule("nav a:hover", "text-decoration: none")
    mut els := Vector {} as Vector<css.Element>
    els.push(css.NewElement("page", -1))
    mut nav := css.NewElement("nav", 0)
    nav.base = "display: flex; gap: 8px; padding: 16px"
    nav.AddMedia("(max-width: 600px)", "flex-direction: column; padding: 8px")
    els.push(nav)
    mut button := css.NewElement("button", 1)
    button.base = "background: #2563eb; color: white; border: none; transition: background 200ms ease-in-out"
    button.hover = "background: #1d4ed8"
    button.active = "transform: scale(0.98)"
    els.push(button)
    mut link := css.NewElement("link", 1)
    link.AddAttr("href", "/help")
    els.push(link)
    _n := sheet.Compute(els, css.Env { width = 900.0, height = 700.0 })
    println "wide", css.ValueText(sheet.Style(1), "flex-direction"), css.ValueText(sheet.Style(1), "padding-top")
    println "button", css.ValueText(sheet.Style(2), "background-color"), css.ValueText(sheet.Style(2), "transition-duration")
    top := css.HoverChain(els, 2)
    println "hover touches", sheet.Restyle(els, top), "elements:", css.ValueText(sheet.Style(2), "background-color")
    mut b := els.ref(2)
    b.pressed = true
    _p := sheet.Restyle(els, 2)
    println "pressed", css.ValueText(sheet.Style(2), "transform")
    top2 := css.HoverChain(els, 3)
    _q := sheet.Restyle(els, top2)
    println "link", css.ValueText(sheet.Style(3), "text-decoration-line"), css.ValueText(sheet.Style(3), "cursor")
    _m := sheet.Compute(els, css.Env { width = 500.0, height = 700.0, dark = true })
    println "narrow", css.ValueText(sheet.Style(1), "flex-direction"), css.ValueText(sheet.Style(1), "padding-top")
    repeat els.len() in i:
        mut x := els.ref(i)
        x.Free()
    end
    els.free()
end
Outputwide row 16px button rgb(37, 99, 235) 0.2s hover touches 3 elements: rgb(29, 78, 216) pressed matrix(0.98, 0, 0, 0.98, 0, 0) link none pointer narrow column 8px

Compiled style programs

A page built with --ui=native does not parse CSS when it runs. At compile time the compiler fills a Program with CompileDecls (one id per distinct declaration list), CompileRule and CompileCss: shorthands are expanded, values are tokenized and validated, selectors and media conditions are compiled, and anything invalid is reported through ProgramErrors. ProgramSource then writes a Salam function that rebuilds the same program from literals, one call per declaration, and the program turns it into a sheet with SheetFromProgram. Elements point at declaration lists through decl_base, decl_hover, decl_focus and decl_active, so computing styles never touches CSS text. Only a style value that is a runtime expression goes through DynDecl, which parses that one value once and caches it. The user agent sheet is itself a generated program, so NewSheet no longer parses CSS either.

gui-css-guide-program.salam
import gui.css
import mem

func styles(): css.Program:
    mut p := css.NewProgram()
    p.AddSimple(3, "card", "", 0, 0, 0, false)
    p.AddCompound(0, 1, 0)
    p.AddSelector(0, 1, 1000, false, false)
    p.AddMedia(-1, [css.Fn(""), css.Kw("max-width"), css.Delim(58, false), css.Dim(600.0, "px"), css.Close()])
    p.AddDecl("padding-top", false, [css.Dim(12.0, "px")])
    p.AddDecl("color", true, [css.Hash("334155")])
    p.AddDecl("font-family", false, [css.KwAs("vazirmatn", "Vazirmatn"), css.Comma(), css.Kw("sans-serif")])
    p.AddDecl("line-height", false, [css.Num(1.5)])
    p.AddDecl("order", false, [css.Int(2.0)])
    p.AddDecl("width", false, [css.Pct(50.0)])
    p.AddDecl("background-image", false, [css.Url("bg.png")])
    p.AddVarDecl("--label", "\"hi\"", false)
    p.EndList(8)
    p.AddDecl("margin-top", false, [css.Str("x")])
    p.EndList(1)
    p.AddRule(0, 0, 0)
    ret p
end

func main:
    mut p := css.NewProgram()
    card := css.CompileDecls(p, "padding: 16px; border-radius: 8px")
    println "list", card, "same text", css.CompileDecls(p, "padding: 16px; border-radius: 8px"), "empty", css.CompileDecls(p, "")
    println "rule", css.CompileRule(p, ".card:hover", "background: #eef", ""), css.CompileRule(p, ".card", "padding: 8px", "(max-width: 600px)")
    println "css rules", css.CompileCss(p, "h1 { margin: 0 } @media (prefers-color-scheme: dark) { body { color: #eee } }")
    _bad := css.CompileDecls(p, "colr: red")
    println "errors", css.ProgramErrors(p)
    e := css.ProgramError(p, 0)
    println e
    mem.Free(e as void*)
    src := css.ProgramSource(p, "page_styles", "css")
    println src.starts_with("func page_styles(): css.Program:")
    mem.Free(src as void*)
    wide := css.DynDecl(p, "width", "240px")
    mut sheet := css.SheetFromProgram(p)
    mut els := Vector {} as Vector<css.Element>
    els.push(css.NewElement("page", -1))
    mut box := css.NewElement("box", 0)
    box.classes = "card"
    box.decl_base = card
    box.decl_hover = -1
    box.decl_focus = -1
    box.decl_active = -1
    box.decl_dyn.push(wide)
    els.push(box)
    _n := sheet.Compute(els, css.Env { width = 500.0 })
    cs := sheet.Style(1)
    println "padding", css.LenText(cs.padding_top), "width", css.LenText(cs.width)
    println "added again", sheet.AddProgram(p)
    mut q := styles()
    piece := css.Kw("auto")
    println "piece", piece.kind, piece.text, piece.raw, piece.num, piece.code, piece.space, "program", q.id >= 0
    repeat els.len() in i:
        mut x := els.ref(i)
        x.Free()
    end
    els.free()
    sheet.Free()
    q.Free()
    p.Free()
end
Outputlist 0 same text 0 empty -1 rule true true css rules 2 errors 1 unknown property 'colr' true padding 16px width 240px added again 0 piece 1 auto 0 0 false program true

Typed values and colours

The program that ProgramSource writes carries values decided at compile time. A declaration is AddTyped with the integer property id from PropertyId; keywords, units and function names are indexes into one name table (KeywordId); lengths keep their number and unit, with absolute units already in pixels and angles in degrees; a calc() that needs nothing from the page is folded to one value; and every colour that does not depend on currentColor is resolved to straight RGBA for the light and the dark scheme. Loading such a program compares no strings and parses nothing.

Colours follow CSS Color 4 and 5: hex, the 148 named colours, transparent, currentColor, rgb(), hsl() and hwb() in the modern and the comma syntax, lab(), lch(), oklab(), oklch(), color() in srgb, srgb-linear, display-p3, a98-rgb, prophoto-rgb, rec2020, xyz, xyz-d50 and xyz-d65, color-mix() in any of those spaces with the four hue interpolation methods, relative colours such as rgb(from red r g calc(b * 2)), light-dark() and the system colours with Chromium's values for each scheme. Every colour inside sRGB matches Chromium; colours outside it are gamut mapped with the CSS Color 4 algorithm, where Chromium clips. Gradients interpolate in the space given with in, and in Oklab when a stop uses one of the newer syntaxes. When the operating system switches between light and dark, SetColorScheme restyles only the elements that depend on the scheme.

gui-css-guide-typed.salam
import gui.css
import mem

func styles(): css.Program:
    mut p := css.NewProgram()
    p.AddTyped(css.PropertyId("display"), 0, [css.KwId(css.KeywordId("flex"))])
    p.AddTyped(css.PropertyId("margin-top"), 0, [css.DimId(1.5, css.KeywordId("em"))])
    p.AddTyped(css.PropertyId("width"), 0, [css.FnId(css.KeywordId("calc")), css.Pct(100.0), css.Delim(45, true), css.DimId(20.0, css.KeywordId("px")), css.Close()])
    p.AddTyped(css.PropertyId("color-scheme"), 2, [css.KwId(css.KeywordId("light")), css.KwId(css.KeywordId("dark"))])
    p.AddTyped(css.PropertyId("color"), 2, [css.ColorValue(0x111111ff, 0xeeeeeeff, 1)])
    p.EndList(5)
    ret p
end

func main:
    name := css.PropertyName(css.PropertyId("color"))
    kw := css.KeywordName(css.KeywordId("flex"))
    println "ids", css.PropertyId("color"), name, css.KeywordId("flex"), kw
    mem.Free(name as void*)
    mem.Free(kw as void*)
    piece := css.ColorValue(0x3366aaff, 0x99bbffff, 1)
    println "piece", piece.id, piece.color, piece.dark, css.KwId(5).id
    mut c := css.Color {}
    _ok := css.ParseColor("oklch(0.7 0.1 30)", c)
    println "oklch", c.r, c.g, c.b
    mixed := css.ColorText(css.MixColors(css.Color { r = 255 }, css.Color { b = 255, a = 0 }, 0.5))
    println "mix", mixed
    mem.Free(mixed as void*)
    mut p := styles()
    mut sheet := css.SheetFromProgram(p)
    mut els := Vector {} as Vector<css.Element>
    els.push(css.NewElement("page", -1))
    mut box := css.NewElement("box", 0)
    box.decl_base = 0
    els.push(box)
    _n := sheet.Compute(els, css.Env { width = 400.0 })
    println "light", css.ValueText(sheet.Style(1), "color"), css.ValueText(sheet.Style(1), "width")
    println "restyled", sheet.SetColorScheme(els, true)
    println "dark", css.ValueText(sheet.Style(1), "color")
    repeat els.len() in i:
        mut x := els.ref(i)
        x.Free()
    end
    els.free()
    sheet.Free()
    p.Free()
end
Outputids 59 color 228 flex piece -1 862366463 2579234815 5 oklch 213 134 121 mix rgba(255, 0, 0, 0.5) light rgb(17, 17, 17) calc(100% - 20px) restyled 2 dark rgb(238, 238, 238)

Types

Piece

struct Piece
One token of a compiled value, as written by ProgramSource. Build it with Kw, Num, Dim and the other constructors rather than by hand.
NameTypeDescription
kindint = 0The token kind.
numf64 = 0The number of a number, dimension or percentage.
textstr = ""The keyword, unit, function name, string, URL or hash text.
rawstr = ""The keyword as written, when it differs from the lower case text (font family names keep their case).
codeint = 0The character of a delimiter, or 1 for a number written as an integer.
spacebool = falseWhether white space came before a delimiter.
idint = -1The index of a keyword, unit or function name in the name table, or -1 when the piece carries its text instead.
colori64 = 0A resolved colour as straight RGBA in one integer, 0xRRGGBBAA, for the light scheme.
darki64 = 0The same colour for the dark scheme; equal to color unless the value used light-dark() or a system colour.
gui-css-Program.salam
import gui.css
import mem

func styles(): css.Program:
    mut p := css.NewProgram()
    p.AddSimple(3, "card", "", 0, 0, 0, false)
    p.AddCompound(0, 1, 0)
    p.AddSelector(0, 1, 1000, false, false)
    p.AddMedia(-1, [css.Fn(""), css.Kw("max-width"), css.Delim(58, false), css.Dim(600.0, "px"), css.Close()])
    p.AddDecl("padding-top", false, [css.Dim(12.0, "px")])
    p.AddDecl("color", true, [css.Hash("334155")])
    p.AddDecl("font-family", false, [css.KwAs("vazirmatn", "Vazirmatn"), css.Comma(), css.Kw("sans-serif")])
    p.AddDecl("line-height", false, [css.Num(1.5)])
    p.AddDecl("order", false, [css.Int(2.0)])
    p.AddDecl("width", false, [css.Pct(50.0)])
    p.AddDecl("background-image", false, [css.Url("bg.png")])
    p.AddVarDecl("--label", "\"hi\"", false)
    p.EndList(8)
    p.AddDecl("margin-top", false, [css.Str("x")])
    p.EndList(1)
    p.AddRule(0, 0, 0)
    ret p
end

func main:
    mut p := css.NewProgram()
    card := css.CompileDecls(p, "padding: 16px; border-radius: 8px")
    println "list", card, "same text", css.CompileDecls(p, "padding: 16px; border-radius: 8px"), "empty", css.CompileDecls(p, "")
    println "rule", css.CompileRule(p, ".card:hover", "background: #eef", ""), css.CompileRule(p, ".card", "padding: 8px", "(max-width: 600px)")
    println "css rules", css.CompileCss(p, "h1 { margin: 0 } @media (prefers-color-scheme: dark) { body { color: #eee } }")
    _bad := css.CompileDecls(p, "colr: red")
    println "errors", css.ProgramErrors(p)
    e := css.ProgramError(p, 0)
    println e
    mem.Free(e as void*)
    src := css.ProgramSource(p, "page_styles", "css")
    println src.starts_with("func page_styles(): css.Program:")
    mem.Free(src as void*)
    wide := css.DynDecl(p, "width", "240px")
    mut sheet := css.SheetFromProgram(p)
    mut els := Vector {} as Vector<css.Element>
    els.push(css.NewElement("page", -1))
    mut box := css.NewElement("box", 0)
    box.classes = "card"
    box.decl_base = card
    box.decl_hover = -1
    box.decl_focus = -1
    box.decl_active = -1
    box.decl_dyn.push(wide)
    els.push(box)
    _n := sheet.Compute(els, css.Env { width = 500.0 })
    cs := sheet.Style(1)
    println "padding", css.LenText(cs.padding_top), "width", css.LenText(cs.width)
    println "added again", sheet.AddProgram(p)
    mut q := styles()
    piece := css.Kw("auto")
    println "piece", piece.kind, piece.text, piece.raw, piece.num, piece.code, piece.space, "program", q.id >= 0
    repeat els.len() in i:
        mut x := els.ref(i)
        x.Free()
    end
    els.free()
    sheet.Free()
    q.Free()
    p.Free()
end
Outputlist 0 same text 0 empty -1 rule true true css rules 2 errors 1 unknown property 'colr' true padding 16px width 240px added again 0 piece 1 auto 0 0 false program true

Program

struct Program
A compiled style program: declaration lists, selectors, media conditions and rules in typed form. A program is a handle; copies share the same data.
NameTypeDescription
idint = -1The handle number, -1 for a program that was not created with NewProgram yet.

The example for this item is shown with the ones above: gui-css-Program.salam

AddDecl

func AddDecl(prop: str, important: bool, value: Piece)
Adds one longhand declaration by property name, with its value as pieces. It still loads programs written before typed values; ProgramSource now writes AddTyped.

The example for this item is shown with the ones above: gui-css-Program.salam

AddTyped

func AddTyped(prop: int, flags: int, value: Piece)
Adds one longhand declaration with a typed value: the integer property id, flags (1 for !important, 2 when the value depends on the colour scheme) and the value as pieces. This is what ProgramSource writes; loading it compares no strings and parses nothing.
gui-css-typed.salam
import gui.css
import mem

func styles(): css.Program:
    mut p := css.NewProgram()
    p.AddTyped(css.PropertyId("display"), 0, [css.KwId(css.KeywordId("flex"))])
    p.AddTyped(css.PropertyId("margin-top"), 0, [css.DimId(1.5, css.KeywordId("em"))])
    p.AddTyped(css.PropertyId("width"), 0, [css.FnId(css.KeywordId("calc")), css.Pct(100.0), css.Delim(45, true), css.DimId(20.0, css.KeywordId("px")), css.Close()])
    p.AddTyped(css.PropertyId("color-scheme"), 2, [css.KwId(css.KeywordId("light")), css.KwId(css.KeywordId("dark"))])
    p.AddTyped(css.PropertyId("color"), 2, [css.ColorValue(0x111111ff, 0xeeeeeeff, 1)])
    p.EndList(5)
    ret p
end

func main:
    name := css.PropertyName(css.PropertyId("color"))
    kw := css.KeywordName(css.KeywordId("flex"))
    println "ids", css.PropertyId("color"), name, css.KeywordId("flex"), kw
    mem.Free(name as void*)
    mem.Free(kw as void*)
    piece := css.ColorValue(0x3366aaff, 0x99bbffff, 1)
    println "piece", piece.id, piece.color, piece.dark, css.KwId(5).id
    mut c := css.Color {}
    _ok := css.ParseColor("oklch(0.7 0.1 30)", c)
    println "oklch", c.r, c.g, c.b
    mixed := css.ColorText(css.MixColors(css.Color { r = 255 }, css.Color { b = 255, a = 0 }, 0.5))
    println "mix", mixed
    mem.Free(mixed as void*)
    mut p := styles()
    mut sheet := css.SheetFromProgram(p)
    mut els := Vector {} as Vector<css.Element>
    els.push(css.NewElement("page", -1))
    mut box := css.NewElement("box", 0)
    box.decl_base = 0
    els.push(box)
    _n := sheet.Compute(els, css.Env { width = 400.0 })
    println "light", css.ValueText(sheet.Style(1), "color"), css.ValueText(sheet.Style(1), "width")
    println "restyled", sheet.SetColorScheme(els, true)
    println "dark", css.ValueText(sheet.Style(1), "color")
    repeat els.len() in i:
        mut x := els.ref(i)
        x.Free()
    end
    els.free()
    sheet.Free()
    p.Free()
end
Outputids 59 color 228 flex piece -1 862366463 2579234815 5 oklch 213 134 121 mix rgba(255, 0, 0, 0.5) light rgb(17, 17, 17) calc(100% - 20px) restyled 2 dark rgb(238, 238, 238)

AddVarDecl

func AddVarDecl(prop: str, value: str, important: bool)
Adds a declaration whose value is kept as text: a custom property, or a value that uses var() and is resolved when styles are computed.

The example for this item is shown with the ones above: gui-css-Program.salam

EndList

func EndList(count: int)
Closes a declaration list made of the last declarations added; its id is the number of lists before it.

The example for this item is shown with the ones above: gui-css-Program.salam

AddMedia

func AddMedia(parent: int, condition: Piece)
Adds a media condition as pieces, with the index of an enclosing condition or -1.

The example for this item is shown with the ones above: gui-css-Program.salam

AddSimple

func AddSimple(kind: int, name: str, value: str, op: int, a: int, b: int, icase: bool)
Adds one simple selector: a type, class, id, attribute, pseudo-class, nth or list selector.

The example for this item is shown with the ones above: gui-css-Program.salam

AddCompound

func AddCompound(first: int, count: int, combinator: int)
Adds a compound selector made of consecutive simple selectors and the combinator before it.

The example for this item is shown with the ones above: gui-css-Program.salam

AddSelector

func AddSelector(first: int, count: int, specificity: int, state_left: bool, sibling: bool)
Adds a complex selector made of consecutive compound selectors, with its specificity.

The example for this item is shown with the ones above: gui-css-Program.salam

AddRule

func AddRule(selector: int, list: int, media: int)
Adds a rule from a selector, a declaration list and a media condition (-1 for none).

The example for this item is shown with the ones above: gui-css-Program.salam

Free

func Free()
Releases the program's data. Sheets made from it keep their own copy.

The example for this item is shown with the ones above: gui-css-Program.salam

ComputedStyle

struct ComputedStyle
Every supported property of an element after the cascade, inheritance and computation: lengths in pixels except percentages that layout must resolve, colours as straight RGBA, keywords as enums.
NameTypeDescription
displayDisplayComputed display.
positioncssbox.PositionComputed position.
topLenComputed top.
rightLenComputed right.
bottomLenComputed bottom.
leftLenComputed left.
box_sizingcssbox.BoxSizingComputed box-sizing.
widthLenComputed width.
heightLenComputed height.
min_widthLenComputed min-width.
min_heightLenComputed min-height.
max_widthLenComputed max-width.
max_heightLenComputed max-height.
aspect_ratiof64 = 0Computed aspect-ratio.
margin_topLenComputed margin-top.
margin_rightLenComputed margin-right.
margin_bottomLenComputed margin-bottom.
margin_leftLenComputed margin-left.
padding_topLenComputed padding-top.
padding_rightLenComputed padding-right.
padding_bottomLenComputed padding-bottom.
padding_leftLenComputed padding-left.
border_topBorderSideComputed border-top.
border_rightBorderSideComputed border-right.
border_bottomBorderSideComputed border-bottom.
border_leftBorderSideComputed border-left.
radius_top_leftCornerComputed border-top-left-radius.
radius_top_rightCornerComputed border-top-right-radius.
radius_bottom_rightCornerComputed border-bottom-right-radius.
radius_bottom_leftCornerComputed border-bottom-left-radius.
overflow_xcssbox.OverflowComputed overflow-x.
overflow_ycssbox.OverflowComputed overflow-y.
directioncssbox.DirectionComputed direction.
flex_directioncssbox.FlexDirectionComputed flex-direction.
flex_wrapcssbox.FlexWrapComputed flex-wrap.
flex_growf64 = 0Computed flex-grow.
flex_shrinkf64 = 1Computed flex-shrink.
flex_basisLenComputed flex-basis.
justify_contentcssbox.AlignComputed justify-content.
align_itemscssbox.AlignComputed align-items.
align_selfcssbox.AlignComputed align-self.
align_contentcssbox.AlignComputed align-content.
justify_itemscssbox.AlignComputed justify-items.
justify_selfcssbox.AlignComputed justify-self.
row_gapLenComputed row-gap.
column_gapLenComputed column-gap.
orderint = 0Computed order.
z_indexint = 0Computed z-index.
z_autobool = trueWhether z-index is auto.
float_modeFloatComputed float.
clearClearComputed clear.
vertical_alignVerticalAlignComputed vertical-align.
vertical_align_lenLenThe length when vertical_align is Length.
colorColorComputed color.
background_colorColorComputed background-color.
backgroundsVectorBackground layers, first on top, combining background-image and the per-layer background properties.
box_shadowsVectorComputed box-shadow.
outlineBorderSideoutline width, style and colour.
outline_offsetf64 = 0Computed outline-offset.
opacityf64 = 1Computed opacity.
transformsVectorComputed transform.
filtersVectorComputed filter, one entry per filter function.
border_imageBorderImageComputed border-image and its longhands. The border shorthand resets it.
backdrop_filtersVectorComputed backdrop-filter.
transform_origin_xLentransform-origin, x.
transform_origin_yLentransform-origin, y.
translate_xLenThe translate property, x.
translate_yLenThe translate property, y.
rotatef64 = 0The rotate property in degrees.
scale_xf64 = 1The scale property, x.
scale_yf64 = 1The scale property, y.
visibilityVisibilityComputed visibility.
cursorstr = "auto"cursor keyword; url() cursors keep only their fallback keyword.
pointer_eventsbool = trueFalse when pointer-events is none.
user_selectUserSelectComputed user-select.
font_familystr = "Times New Roman"font-family as a list separated by ", "; see FontFamilies. The initial value is Times New Roman, as in Chromium.
font_sizef64 = 16Computed font-size.
font_size_keywordf64 = 1The font size as a multiple of medium while it derives from a keyword, used to size monospace text like Chromium; zero otherwise.
font_weightint = 400Computed font-weight.
font_styleFontStyleComputed font-style.
small_capsbool = falseComputed font-variant-caps.
font_stretchf64 = 100Computed font-stretch.
line_heightf64 = 19.2line-height in pixels.
line_height_factorf64 = 0The number when line-height is a plain number (it is inherited as a number); otherwise zero.
line_height_normalbool = trueWhether line-height is normal; line_height then holds 1.2 times the font size until the text package measures the font.
letter_spacingf64 = 0Computed letter-spacing.
word_spacingf64 = 0Computed word-spacing.
text_alignTextAlignComputed text-align.
text_indentLenComputed text-indent.
text_transformTextTransformComputed text-transform.
white_spaceWhiteSpaceComputed white-space.
underlinebool = falsetext-decoration-line has underline.
overlinebool = falsetext-decoration-line has overline.
line_throughbool = falsetext-decoration-line has line-through.
decoration_styleDecorationStyleComputed text-decoration-style.
decoration_colorColorComputed text-decoration-color.
decoration_thicknessLenComputed text-decoration-thickness.
text_shadowsVectorComputed text-shadow.
text_overflowTextOverflowComputed text-overflow.
word_breakWordBreakComputed word-break.
overflow_wrapOverflowWrapComputed overflow-wrap.
tab_sizef64 = 8tab-size as a number of spaces, zero when given as a length.
tab_size_pxf64 = 0tab-size in pixels when given as a length.
list_style_typestr = "disc"Computed list-style-type.
list_style_positionListPositionComputed list-style-position.
list_style_imagestr = ""Computed list-style-image.
border_collapseBorderCollapseComputed border-collapse.
border_spacing_xf64 = 0Horizontal border-spacing.
border_spacing_yf64 = 0Vertical border-spacing.
table_layoutTableLayoutComputed table-layout.
caption_sidecssbox.CaptionSideComputed caption-side of a table caption.
grid_template_columnsstr = ""Computed grid-template-columns as CSS text with lengths in pixels, or empty for none.
grid_template_rowsstr = ""Computed grid-template-rows, or empty for none.
grid_template_areasstr = ""Computed grid-template-areas as quoted rows, or empty for none.
grid_auto_columnsstr = ""Computed grid-auto-columns, or empty for auto.
grid_auto_rowsstr = ""Computed grid-auto-rows, or empty for auto.
grid_auto_flowcssbox.GridAutoFlowComputed grid-auto-flow.
grid_row_startstr = ""Computed grid-row-start, or empty for auto.
grid_row_endstr = ""Computed grid-row-end, or empty for auto.
grid_column_startstr = ""Computed grid-column-start, or empty for auto.
grid_column_endstr = ""Computed grid-column-end, or empty for auto.
transitionsVectorTransitions, combining the four transition-* lists.
caret_colorColorComputed caret-color.
accent_colorColorComputed accent-color.
accent_autobool = trueWhether accent-color is auto; accent_color then holds the system accent.
appearancestr = "none"appearance; form controls with auto are painted in the native look.
color_schemeColorSchemeComputed color-scheme.
used_darkbool = falseWhether system colours resolve to their dark variants for this element (from color-scheme and the environment).
object_fitObjectFitComputed object-fit.
object_position_xLenobject-position, x.
object_position_yLenobject-position, y.
gui-css-ComputedStyle.salam
import gui.css

func main:
    mut sheet := css.NewSheet()
    defer sheet.Free()
    mut els := Vector {} as Vector<css.Element>
    mut root := css.NewElement("page", -1)
    root.base = "color: #222; font: 16px/1.5 Vazirmatn, sans-serif"
    els.push(root)
    mut card := css.NewElement("box", 0)
    card.base = `display: flex; position: relative; top: 4px; flex-flow: row wrap; gap: 8px 2%; padding: 12px 16px; margin: 0 auto; border: 2px solid #ccc; border-radius: 12px; background: linear-gradient(to right, #fff 0%, #eee 100%), url(bg.png) center / cover no-repeat, #fafafa; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); outline: 1px dashed red; outline-offset: 2px; opacity: 0.9; transform: rotate(5deg) scale(1.1); transform-origin: left top; translate: 4px 2px; rotate: 10deg; scale: 2; transition: opacity 300ms ease-out 100ms; cursor: pointer; z-index: 3; text-align: center; text-shadow: 1px 1px 2px black; letter-spacing: 1px; word-spacing: 2px; text-decoration: underline overline line-through wavy red 2px; list-style: square inside; caret-color: blue; accent-color: green; color-scheme: light dark; aspect-ratio: 4 / 3; overflow: hidden auto; white-space: nowrap; text-overflow: ellipsis; word-break: break-all; overflow-wrap: anywhere; tab-size: 4; vertical-align: middle; float: left; clear: both; user-select: none; pointer-events: none; visibility: visible; object-fit: cover; object-position: right bottom; border-collapse: collapse; border-spacing: 2px 4px; table-layout: fixed; appearance: none; font-style: italic; font-variant-caps: small-caps; font-stretch: condensed; text-transform: uppercase; text-indent: 1em; order: 2; flex-grow: 1; flex-shrink: 0; flex-basis: 50%; justify-content: center; align-items: stretch; align-self: flex-start; align-content: space-around; justify-items: start; justify-self: end; box-sizing: border-box; direction: ltr; min-width: 100px; max-width: 800px; min-height: 2em; max-height: none; width: 50%; height: auto; right: auto; bottom: auto; left: 0`
    els.push(card)
    _n := sheet.Compute(els, css.Env {})
    cs := sheet.Style(1)
    println cs.display, cs.position, css.LenText(cs.top), css.LenText(cs.right), css.LenText(cs.bottom), css.LenText(cs.left)
    println cs.box_sizing, css.LenText(cs.width), css.LenText(cs.height), css.LenText(cs.min_width), css.LenText(cs.min_height), css.LenText(cs.max_width)
    println css.LenText(cs.max_height), cs.aspect_ratio, css.LenText(cs.margin_top), css.LenText(cs.margin_right), css.LenText(cs.margin_bottom), css.LenText(cs.margin_left)
    println css.LenText(cs.padding_top), css.LenText(cs.padding_right), css.LenText(cs.padding_bottom), css.LenText(cs.padding_left), cs.border_top.width, cs.border_top.style
    println css.ColorText(cs.border_top.color), cs.border_right.width, cs.border_right.style, css.ColorText(cs.border_right.color), cs.border_bottom.width, cs.border_bottom.style
    println css.ColorText(cs.border_bottom.color), cs.border_left.width, cs.border_left.style, css.ColorText(cs.border_left.color), css.LenText(cs.radius_top_left.h), css.LenText(cs.radius_top_left.v)
    println css.LenText(cs.radius_top_right.h), css.LenText(cs.radius_top_right.v), css.LenText(cs.radius_bottom_right.h), css.LenText(cs.radius_bottom_right.v), css.LenText(cs.radius_bottom_left.h), css.LenText(cs.radius_bottom_left.v)
    println cs.overflow_x, cs.overflow_y, cs.direction, cs.flex_direction, cs.flex_wrap, cs.flex_grow
    println cs.flex_shrink, css.LenText(cs.flex_basis), cs.justify_content, cs.align_items, cs.align_self, cs.align_content
    println cs.justify_items, cs.justify_self, css.LenText(cs.row_gap), css.LenText(cs.column_gap), cs.order, cs.z_index
    println cs.z_auto, cs.float_mode, cs.clear, cs.vertical_align, css.LenText(cs.vertical_align_len), css.ColorText(cs.color)
    println css.ColorText(cs.background_color), cs.backgrounds.len(), cs.box_shadows.len(), cs.outline.width, cs.outline.style, css.ColorText(cs.outline.color)
    println cs.outline_offset, cs.opacity, cs.transforms.len(), css.LenText(cs.transform_origin_x), css.LenText(cs.transform_origin_y), css.LenText(cs.translate_x)
    println css.LenText(cs.translate_y), cs.rotate, cs.scale_x, cs.scale_y, cs.visibility, "[" + cs.cursor + "]"
    println cs.pointer_events, cs.user_select, "[" + cs.font_family + "]", cs.font_size, cs.font_size_keyword, cs.font_weight
    println cs.font_style, cs.small_caps, cs.font_stretch, cs.line_height, cs.line_height_factor, cs.line_height_normal
    println cs.letter_spacing, cs.word_spacing, cs.text_align, css.LenText(cs.text_indent), cs.text_transform, cs.white_space
    println cs.underline, cs.overline, cs.line_through, cs.decoration_style, css.ColorText(cs.decoration_color), css.LenText(cs.decoration_thickness)
    println cs.text_shadows.len(), cs.text_overflow, cs.word_break, cs.overflow_wrap, cs.tab_size, cs.tab_size_px
    println "[" + cs.list_style_type + "]", cs.list_style_position, "[" + cs.list_style_image + "]", cs.border_collapse, cs.border_spacing_x, cs.border_spacing_y
    println cs.table_layout, cs.transitions.len(), css.ColorText(cs.caret_color), css.ColorText(cs.accent_color), cs.accent_auto, "[" + cs.appearance + "]"
    println cs.color_scheme, cs.used_dark, cs.object_fit, css.LenText(cs.object_position_x), css.LenText(cs.object_position_y)
    l := cs.backgrounds[0]
    println l.image, l.url.len(), l.repeating, l.angle, l.to_x, l.to_y, l.shape, l.extent, css.LenText(l.radius_x), css.LenText(l.radius_y), css.LenText(l.center_x), css.LenText(l.center_y)
    println l.stops.len(), css.LenText(l.position_x), css.LenText(l.position_y), l.size_kind, css.LenText(l.size_w), css.LenText(l.size_h), l.repeat_x, l.repeat_y, l.clip, l.origin, l.fixed
    st := l.stops[1]
    println css.ColorText(st.color), css.LenText(st.pos), st.has_pos, st.hint
    u := cs.backgrounds[1]
    println u.image, u.url, u.size_kind, u.repeat_x
    s := cs.box_shadows[0]
    println s.x, s.y, s.blur, s.spread, css.ColorText(s.color), s.inset
    f := cs.transforms[1]
    println f.kind, css.LenText(f.x), css.LenText(f.y), f.a, f.b, f.c, f.d, f.e, f.f
    t := cs.transitions[0]
    println t.property, t.duration, t.delay, t.timing.kind
    repeat els.len() in i:
        mut x := els.ref(i)
        x.Free()
    end
    els.free()
end
Output4 1 4px auto auto 0px 1 50% auto 100px 32px 800px none 1.3333333333333333 0px auto 0px auto 12px 16px 12px 16px 2 2 rgb(204, 204, 204) 2 2 rgb(204, 204, 204) 2 2 rgb(204, 204, 204) 2 2 rgb(204, 204, 204) 12px 12px 12px 12px 12px 12px 12px 12px 1 4 0 0 1 1 0 50% 6 8 4 10 2 3 8px 2% 2 3 false 1 3 5 0px rgb(34, 34, 34) rgb(250, 250, 250) 3 1 1 3 rgb(255, 0, 0) 2 0.9 2 0% 0% 4px 2px 10 2 2 0 [pointer] false 1 [Vazirmatn, sans-serif] 16 0 400 1 true 75 24 1.5 false 1 2 4 16px 2 2 true true true 4 rgb(255, 0, 0) 2px 1 1 1 1 4 0 [square] 1 [] 1 2 4 1 1 rgb(0, 0, 255) rgb(0, 128, 0) false [none] 3 false 2 100% 100% 2 0 false 90 0 0 0 0 0px 0px 50% 50% 2 0% 0% 0 auto auto 0 0 0 1 false rgb(238, 238, 238) 100% true false 1 bg.png 1 1 0 2 6 0 rgba(0, 0, 0, 0.2) false 1 0px 0px 1.1 0 0 1.1 0 0 opacity 300 100 1

Display

enum Display
The computed display, after blockification of flex items, floats, absolutely positioned boxes and the root.
NameTypeDescription
BlockThe block value.
InlineThe inline value.
InlineBlockThe inline-block value.
FlowRootThe flow-root value.
FlexThe flex value.
InlineFlexThe inline-flex value.
GridThe grid value.
InlineGridThe inline-grid value.
ListItemThe list-item value.
TableThe table value.
InlineTableThe inline-table value.
TableRowGroupThe table-row-group value.
TableHeaderGroupThe table-header-group value.
TableFooterGroupThe table-footer-group value.
TableRowThe table-row value.
TableCellThe table-cell value.
TableColumnThe table-column value.
TableColumnGroupThe table-column-group value.
TableCaptionThe table-caption value.
Contentscontents: the children take the box's place.
Nonenone: no box.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

LenKind

enum LenKind
What a Len holds.
NameTypeDescription
AutoThe auto value.
LengthA length or percentage.
NoneThe none value.
NormalThe normal value.
MinContentThe min-content value.
MaxContentThe max-content value.
FitContentThe fit-content value.
ContentThe content value.
NumberA plain number, used by border-image widths, outsets and slices: px holds the number.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

BorderStyle

enum BorderStyle
A border or outline line style.
NameTypeDescription
NoneThe none value.
HiddenThe hidden value.
SolidThe solid value.
DashedThe dashed value.
DottedThe dotted value.
DoubleThe double value.
GrooveThe groove value.
RidgeThe ridge value.
InsetThe inset value.
OutsetThe outset value.
AutoThe outline-only auto style, drawn as a focus ring.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

Visibility

enum Visibility
visibility.
NameTypeDescription
VisibleThe visible value.
HiddenThe hidden value.
CollapseThe collapse value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

TextAlign

enum TextAlign
text-align; start and end follow the direction.
NameTypeDescription
StartThe start value.
EndThe end value.
LeftThe left value.
RightThe right value.
CenterThe center value.
JustifyThe justify value.
MatchParentThe match-parent value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

TextTransform

enum TextTransform
text-transform.
NameTypeDescription
NoneThe none value.
CapitalizeThe capitalize value.
UppercaseThe uppercase value.
LowercaseThe lowercase value.
FullWidthThe full-width value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

WhiteSpace

enum WhiteSpace
white-space.
NameTypeDescription
NormalThe normal value.
PreThe pre value.
NoWrapThe nowrap value.
PreWrapThe pre-wrap value.
PreLineThe pre-line value.
BreakSpacesThe break-spaces value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

FontStyle

enum FontStyle
font-style.
NameTypeDescription
NormalThe normal value.
ItalicThe italic value.
ObliqueThe oblique value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

ImageKind

enum ImageKind
What a background layer image is.
NameTypeDescription
NoneNo image.
UrlA url() image.
LinearA linear gradient.
RadialA radial gradient.
ConicA conic gradient.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

RadialShape

enum RadialShape
Radial gradient shape.
NameTypeDescription
EllipseThe ellipse value.
CircleThe circle value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

RadialExtent

enum RadialExtent
Radial gradient size.
NameTypeDescription
FarthestCornerThe farthest-corner value.
FarthestSideThe farthest-side value.
ClosestCornerThe closest-corner value.
ClosestSideThe closest-side value.
ExplicitRadii given as lengths.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

SizeKind

enum SizeKind
background-size mode.
NameTypeDescription
ExplicitWidth and height given (each may be auto).
CoverThe cover value.
ContainThe contain value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

Repeat

enum Repeat
background-repeat per axis.
NameTypeDescription
RepeatThe repeat value.
NoRepeatThe no-repeat value.
SpaceThe space value.
RoundThe round value.
StretchThe stretch value of border-image-repeat.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

BoxArea

enum BoxArea
A box for background-clip and background-origin.
NameTypeDescription
BorderBoxThe border-box value.
PaddingBoxThe padding-box value.
ContentBoxThe content-box value.
TextThe text value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

TransformKind

enum TransformKind
A transform function.
NameTypeDescription
Translatetranslate() and its axis forms.
Scalescale(); 3D rotations and perspective are kept as an identity scale.
Rotaterotate().
Skewskew(), skewX(), skewY().
Matrixmatrix(), or the 2D part of matrix3d().

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

TimingKind

enum TimingKind
A timing function kind.
NameTypeDescription
LinearThe linear value.
CubicBezierA cubic Bezier curve.
Stepssteps().

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

StepPosition

enum StepPosition
Where steps() jumps.
NameTypeDescription
JumpEndThe jump-end value.
JumpStartThe jump-start value.
JumpNoneThe jump-none value.
JumpBothThe jump-both value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

DecorationStyle

enum DecorationStyle
text-decoration-style.
NameTypeDescription
SolidThe solid value.
DoubleThe double value.
DottedThe dotted value.
DashedThe dashed value.
WavyThe wavy value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

ListPosition

enum ListPosition
list-style-position.
NameTypeDescription
OutsideThe outside value.
InsideThe inside value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

Float

enum Float
float, with logical values resolved.
NameTypeDescription
NoneThe none value.
LeftThe left value.
RightThe right value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

Clear

enum Clear
clear.
NameTypeDescription
NoneThe none value.
LeftThe left value.
RightThe right value.
BothThe both value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

VerticalAlign

enum VerticalAlign
vertical-align.
NameTypeDescription
BaselineThe baseline value.
SubThe sub value.
SuperThe super value.
TopThe top value.
TextTopThe text-top value.
MiddleThe middle value.
BottomThe bottom value.
TextBottomThe text-bottom value.
LengthA length or percentage in vertical_align_len.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

WordBreak

enum WordBreak
word-break.
NameTypeDescription
NormalThe normal value.
BreakAllThe break-all value.
KeepAllThe keep-all value.
BreakWordThe break-word value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

OverflowWrap

enum OverflowWrap
overflow-wrap.
NameTypeDescription
NormalThe normal value.
AnywhereThe anywhere value.
BreakWordThe break-word value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

TextOverflow

enum TextOverflow
text-overflow.
NameTypeDescription
ClipThe clip value.
EllipsisThe ellipsis value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

BorderCollapse

enum BorderCollapse
border-collapse.
NameTypeDescription
SeparateThe separate value.
CollapseThe collapse value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

TableLayout

enum TableLayout
table-layout.
NameTypeDescription
AutoThe auto value.
FixedThe fixed value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

UserSelect

enum UserSelect
user-select.
NameTypeDescription
AutoThe auto value.
NoneThe none value.
TextThe text value.
AllThe all value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

ColorScheme

enum ColorScheme
color-scheme.
NameTypeDescription
NormalThe normal value.
LightThe light value.
DarkThe dark value.
LightDarklight dark: follows the system scheme.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

ObjectFit

enum ObjectFit
object-fit.
NameTypeDescription
FillThe fill value.
ContainThe contain value.
CoverThe cover value.
NoneThe none value.
ScaleDownThe scale-down value.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

Color

struct Color
A colour as straight (not premultiplied) 8-bit red, green, blue and alpha.
NameTypeDescription
rint = 0Red, 0 to 255.
gint = 0Green, 0 to 255.
bint = 0Blue, 0 to 255.
aint = 255Alpha, 0 (transparent) to 255 (opaque).
legacybool = trueWhether the colour was written as hex, a name, rgb(), hsl() or hwb(). Transitions and gradients between legacy colours stay in sRGB; any other colour makes them use Oklab.
gui-css-values.salam
import gui.css
import mem

func main:
    mut c := css.Color {}
    ok := css.ParseColor("hsl(210 80% 50% / 0.5)", c)
    t := css.ColorText(c)
    println ok, c.r, c.g, c.b, c.a, t
    mem.Free(t as void*)
    mut ds := css.ParseDeclarations("margin: 4px 8px; color: red !important; --x: 1")
    repeat ds.len() in i:
        d := ds[i]
        println d.name, d.value, d.important
    end
    css.FreeDeclarations(ds)
    sp := css.SelectorSpecificity("#nav .item:hover > a")
    println "specificity", sp.ids, sp.classes, sp.types
    env := css.Env { width = 500.0, height = 800.0 }
    println "media", css.MediaMatches("(max-width: 600px) and (orientation: portrait)", env)
    ease := css.Timing {}
    println "ease", ease.kind, ease.x1, ease.y1, ease.x2, ease.y2, ease.steps, ease.step_position, css.EasingAt(ease, 0.5) > 0.8
    steps := css.Timing { kind = css.TimingKind.Steps, steps = 4, step_position = css.StepPosition.JumpEnd }
    println "steps", css.EasingAt(steps, 0.6)
    mut sheet := css.NewSheet()
    defer sheet.Free()
    mut els := Vector {} as Vector<css.Element>
    els.push(css.NewElement("page", -1))
    mut box := css.NewElement("box", 0)
    box.base = "width: calc(100% - 2em); height: min(50vh, 300px); border-radius: 20px / 10px; transform: translate(10px, 0) rotate(90deg); font-family: Vazirmatn, Tahoma, sans-serif; display: flex; padding: 1em"
    els.push(box)
    _n := sheet.Compute(els, env)
    cs := sheet.Style(1)
    w := cs.width
    wtext := css.LenText(w)
    println "width", wtext, w.kind, w.px, w.pct, w.has_pct, w.calc.len() == 0, css.Resolve(w, 300.0)
    mem.Free(wtext as void*)
    println "needs basis", css.NeedsBasis(cs)
    b := css.ToBox(cs)
    bi := css.ToBoxIn(cs, 300.0, 200.0)
    println "box", b.display, b.width.kind, bi.width.value, bi.height.value
    m := css.TransformMatrix(cs, 100.0, 40.0)
    println "matrix", m.a, m.b, m.c, m.d, m.e, m.f
    r := css.UsedRadii(cs, 30.0, 40.0)
    println "radii", r.top_left_x, r.top_left_y, r.top_right_x, r.top_right_y, r.bottom_right_x, r.bottom_right_y, r.bottom_left_x, r.bottom_left_y
    mut fams := css.FontFamilies(cs)
    println "families", fams.len(), fams[0], fams[2]
    fams.free()
    v := css.ValueText(cs, "border-top-left-radius")
    println "value text", v
    mem.Free(v as void*)
    repeat els.len() in i:
        mut x := els.ref(i)
        x.Free()
    end
    els.free()
end
Outputtrue 26 128 230 128 rgba(26, 128, 230, 0.5) margin-top 4px false margin-right 8px false margin-bottom 4px false margin-left 8px false color red true --x 1 false specificity 1 2 1 media true ease 1 0.25 0.1 0.25 1 1 0 true steps 0.5 width calc(100% - 32px) 1 -32 100 true true 268 needs basis true box 3 1 268 300 matrix 0 1 -1 0 80 -30 radii 15 7.5 15 7.5 15 7.5 15 7.5 families 3 Vazirmatn sans-serif value text 20px 10px

Len

struct Len
A computed length: pixels, a percentage still to be resolved, both, a calc() expression that mixes them non-linearly, or a keyword such as auto.
NameTypeDescription
kindLenKindWhether this is a length or a keyword.
pxf64 = 0The pixel part.
pctf64 = 0The percentage part, 50 for 50%.
has_pctbool = falseWhether a percentage part is present.
calcstr = ""A min(), max() or calc() expression in pixels and percentages when the value is not linear; resolve it with Resolve.

The example for this item is shown with the ones above: gui-css-values.salam

Corner

struct Corner
One corner radius with its horizontal and vertical parts.
NameTypeDescription
hLenHorizontal radius.
vLenVertical radius.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

BorderSide

struct BorderSide
Width, style and colour of one border side or of the outline.
NameTypeDescription
widthf64 = 0Width in pixels, zero when the style is none or hidden, and snapped to whole pixels like Chromium.
styleBorderStyleThe line style.
colorColorThe colour, currentColor already resolved.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

Shadow

struct Shadow
One box or text shadow.
NameTypeDescription
xf64 = 0Horizontal offset in pixels.
yf64 = 0Vertical offset in pixels.
blurf64 = 0Blur radius in pixels.
spreadf64 = 0Spread in pixels; always zero for text shadows.
colorColorThe colour.
insetbool = falseWhether this is an inner shadow.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

ColorStop

struct ColorStop
One colour stop or colour hint of a gradient.
NameTypeDescription
colorColorThe colour.
posLenThe position; for conic gradients the pixel part holds degrees.
has_posbool = falseWhether a position was given.
hintbool = falseWhether this is a bare position that moves the midpoint between two colours.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

BgLayer

struct BgLayer
One background layer: its image and the per-layer background properties.
NameTypeDescription
imageImageKindWhat the image is.
urlstr = ""The address of a url() image.
repeatingbool = falseWhether the gradient is a repeating one.
anglef64 = 180Linear gradient angle in degrees, or the from angle of a conic gradient.
to_xint = 0For to a corner: -1 left, 1 right; zero when the angle is used.
to_yint = 0For to a corner: -1 top, 1 bottom.
shapeRadialShapeRadial gradient shape.
extentRadialExtentRadial gradient size keyword, or explicit radii.
radius_xLenExplicit horizontal radius.
radius_yLenExplicit vertical radius.
center_xLenCentre of a radial or conic gradient.
center_yLenVertical centre.
stopsVectorThe colour stops.
position_xLenbackground-position-x.
position_yLenbackground-position-y.
size_kindSizeKindcover, contain or explicit sizes.
size_wLenExplicit width, or auto.
size_hLenExplicit height, or auto.
repeat_xRepeatHorizontal repeat.
repeat_yRepeatVertical repeat.
clipBoxAreabackground-clip.
originBoxAreabackground-origin.
interpolationint = 0The colour space the gradient interpolates in, as a number: 0 srgb, 1 srgb-linear, 2 display-p3, 3 a98-rgb, 4 prophoto-rgb, 5 rec2020, 6 xyz-d50, 7 xyz-d65, 8 lab, 9 lch, 10 oklab, 11 oklch, 12 hsl, 13 hwb. Without in it is srgb when every stop is a legacy colour and oklab otherwise.
hue_interpolationint = 0The hue method for the polar spaces: 0 shorter, 1 longer, 2 increasing, 3 decreasing.
interpolation_setbool = falseWhether the gradient named its space with in.
fixedbool = falseWhether background-attachment is fixed.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

BorderImage

struct BorderImage
The computed border-image: the image, how it is cut, how wide the parts are drawn, how far they reach outside the border box and how the edges repeat.
NameTypeDescription
sourceBgLayerborder-image-source: a gradient or url() layer, or an image of kind none.
slice_topLenThe top slice: a LenKind.Number in image pixels or a percentage of the image height.
slice_rightLenThe right slice.
slice_bottomLenThe bottom slice.
slice_leftLenThe left slice.
fillbool = falseWhether border-image-slice has fill, which draws the middle of the image too.
width_topLenThe top border-image-width: a number times the border width, a length, a percentage of the border image area, or auto.
width_rightLenThe right width.
width_bottomLenThe bottom width.
width_leftLenThe left width.
outset_topLenThe top border-image-outset: a number times the border width, or a length.
outset_rightLenThe right outset.
outset_bottomLenThe bottom outset.
outset_leftLenThe left outset.
repeat_xRepeatHow the top and bottom edges repeat: stretch, repeat, round or space.
repeat_yRepeatHow the left and right edges repeat.
gui-css-BorderImage.salam
import gui.css

func main:
    mut sheet := css.NewSheet()
    defer sheet.Free()
    mut els := Vector {} as Vector<css.Element>
    mut card := css.NewElement("box", -1)
    card.base = "border: 8px solid; border-image: linear-gradient(45deg, red, blue) 30% fill / 2 / 4px round stretch; background: linear-gradient(90deg in oklch, oklch(70% 0.15 30), 25%, oklch(60% 0.12 250))"
    els.push(card)
    _n := sheet.Compute(els, css.Env {})
    cs := sheet.Style(0)
    bi := cs.border_image
    println "source:", css.ValueText(cs, "border-image-source")
    println "slice:", css.LenText(bi.slice_top), css.LenText(bi.slice_right), css.LenText(bi.slice_bottom), css.LenText(bi.slice_left), "fill", bi.fill
    println "width:", bi.width_top.kind == css.LenKind.Number, bi.width_top.px, bi.width_right.px, bi.width_bottom.px, bi.width_left.px
    println "outset:", css.LenText(bi.outset_top), css.LenText(bi.outset_right), css.LenText(bi.outset_bottom), css.LenText(bi.outset_left)
    println "repeat:", bi.repeat_x == css.Repeat.Round, bi.repeat_y == css.Repeat.Stretch, bi.source.image == css.ImageKind.Linear
    bg := cs.backgrounds[0]
    println "gradient space:", bg.interpolation, "hue:", bg.hue_interpolation, "written:", bg.interpolation_set
    mut stops := css.GradientStops(bg, 200.0)
    first := stops[0]
    last := stops[stops.len() - 1]
    println "stops at paint time:", stops.len(), css.ColorText(first.color), "at", first.pos.px, "to", css.ColorText(last.color), "at", last.pos.px
    stops.free()
    mut a := css.Color {}
    mut b := css.Color {}
    _x := css.ParseColor("oklch(70% 0.15 30)", a)
    _y := css.ParseColor("oklch(60% 0.12 250)", b)
    m := css.MixColors(a, b, 0.5)
    println "legacy:", a.legacy, "transition midpoint:", css.ColorText(m)
    els[0].Free()
    els.free()
end
Outputsource: linear-gradient(45deg, rgb(255, 0, 0), rgb(0, 0, 255)) slice: 30% 30% 30% 30% fill true width: true 2 2 2 2 outset: 4px 4px 4px 4px repeat: true true true gradient space: 11 hue: 0 written: true stops at paint time: 81 rgb(237, 118, 101) at 0 to rgb(66, 132, 197) at 200 legacy: false transition midpoint: rgb(163, 132, 154)

TransformFn

struct TransformFn
One function of a transform list.
NameTypeDescription
kindTransformKindWhich function.
xLenTranslate x.
yLenTranslate y.
af64 = 1Scale x, rotation in degrees, skew x in degrees, or matrix a.
bf64 = 0Skew y in degrees, or matrix b.
cf64 = 0Matrix c.
df64 = 1Scale y, or matrix d.
ef64 = 0Matrix e.
ff64 = 0Matrix f.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

FilterFn

struct FilterFn
One function of a filter or backdrop-filter list.
NameTypeDescription
namestr = ""The function name: blur, brightness, contrast, grayscale, sepia, saturate, hue-rotate, invert, opacity or drop-shadow.
amountf64 = 0The amount: pixels for blur, degrees for hue-rotate, a factor for the rest (percentages become fractions).
shadowShadowThe shadow of drop-shadow.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

Matrix

struct Matrix
A 2D affine matrix [a c e; b d f], as in CSS matrix().
NameTypeDescription
af64 = 1Row 1, column 1.
bf64 = 0Row 2, column 1.
cf64 = 0Row 1, column 2.
df64 = 1Row 2, column 2.
ef64 = 0Horizontal translation.
ff64 = 0Vertical translation.

The example for this item is shown with the ones above: gui-css-values.salam

Timing

struct Timing
A timing function: a cubic Bezier curve (keywords such as ease become one), linear or steps(). The default is ease.
NameTypeDescription
kindTimingKindWhich kind of function.
x1f64 = 0.25First control point x.
y1f64 = 0.1First control point y.
x2f64 = 0.25Second control point x.
y2f64 = 1Second control point y.
stepsint = 1Number of steps.
step_positionStepPositionWhere the jumps happen.

The example for this item is shown with the ones above: gui-css-values.salam

Transition

struct Transition
One transition of an element.
NameTypeDescription
propertystr = "all"The property name, or all.
durationf64 = 0Duration in milliseconds.
delayf64 = 0Delay in milliseconds.
timingTimingThe timing function.

The example for this item is shown with the ones above: gui-css-ComputedStyle.salam

Radii

struct Radii
Used corner radii in pixels, from UsedRadii.
NameTypeDescription
top_left_xf64 = 0The horizontal radius of the top left corner.
top_left_yf64 = 0The vertical radius of the top left corner.
top_right_xf64 = 0The horizontal radius of the top right corner.
top_right_yf64 = 0The vertical radius of the top right corner.
bottom_right_xf64 = 0The horizontal radius of the bottom right corner.
bottom_right_yf64 = 0The vertical radius of the bottom right corner.
bottom_left_xf64 = 0The horizontal radius of the bottom left corner.
bottom_left_yf64 = 0The vertical radius of the bottom left corner.

The example for this item is shown with the ones above: gui-css-values.salam

Specificity

struct Specificity
A selector specificity: ids, then classes, attributes and pseudo-classes, then types.
NameTypeDescription
idsint = 0Number of id selectors.
classesint = 0Number of class, attribute and pseudo-class selectors.
typesint = 0Number of type selectors.

The example for this item is shown with the ones above: gui-css-values.salam

Declaration

struct Declaration
One parsed declaration.
NameTypeDescription
namestr = ""Property name, a longhand after expansion.
valuestr = ""The value text.
importantbool = falseWhether it was marked !important.

The example for this item is shown with the ones above: gui-css-values.salam

Env

struct Env
What media queries and viewport units see: the window size, colour scheme, reduced motion, pointer abilities, and the page direction and language.
NameTypeDescription
widthf64 = 1024Viewport width in pixels.
heightf64 = 768Viewport height in pixels.
darkbool = falseWhether the system uses a dark colour scheme.
reduced_motionbool = falseWhether the user asked for less motion.
hoverbool = trueWhether the main pointer can hover.
fine_pointerbool = trueWhether the main pointer is precise, like a mouse.
dirstr = "ltr"The page direction on the root, ltr or rtl.
langstr = "en"The page language on the root.
gui-css-Sheet.salam
import gui.css
import mem

func main:
    mut sheet := css.NewSheet()
    defer sheet.Free()
    println "rules", sheet.RuleCount() > 100
    _a := sheet.AddRule(".card > p:first-child", "color: #334155; margin: 0 0 8px")
    _b := sheet.AddMediaRule("(max-width: 600px)", ".card", "padding: 8px")
    println "css rules", sheet.AddCss("@media (prefers-color-scheme: dark) { body { background: #111 } } a:hover { color: red }")
    mut els := Vector {} as Vector<css.Element>
    mut body := css.NewElement("page", -1)
    body.base = "font-family: Vazirmatn, sans-serif; --gap: 12px"
    els.push(body)
    mut card := css.NewElement("box", 0)
    card.id = "main"
    card.classes = "card"
    card.base = "display: flex; gap: var(--gap); padding: 16px"
    card.AddMedia("(min-width: 1200px)", "padding: 32px")
    els.push(card)
    mut p := css.NewElement("paragraph", 1)
    p.AddAttr("lang", "en")
    els.push(p)
    mut link := css.NewElement("link", 1)
    link.AddAttr("href", "/next")
    link.hover = "text-decoration: none"
    link.focus = "outline: 2px solid blue"
    link.active = "color: purple"
    els.push(link)
    println "tag", link.tag, link.kind, link.parent, link.HasAttr("href")
    env := css.Env { width = 800.0, height = 600.0, dark = false, reduced_motion = false, hover = true, fine_pointer = true, dir = "ltr", lang = "en" }
    println "distinct", sheet.Compute(els, env), "elements", sheet.Count()
    cs := sheet.Style(2)
    println "p", css.ValueText(cs, "color"), css.ValueText(cs, "margin-top"), css.ValueText(cs, "margin-bottom")
    println "card", css.ValueText(sheet.Style(1), "column-gap"), css.ValueText(sheet.Style(1), "padding-top")
    println "root", css.ValueText(sheet.RootStyle(), "display"), "same style", sheet.StyleId(2) == sheet.StyleId(2)
    g := sheet.Var(2, "--gap")
    println "var", g
    mem.Free(g as void*)
    println "matches", sheet.Matches("#main > a[href]", els, 3)
    top := css.HoverChain(els, 3)
    println "hovered", els[3].hovered, els[1].hovered, "restyled", sheet.Restyle(els, top)
    println "after hover", css.ValueText(sheet.Style(3), "text-decoration-line"), "cascades", sheet.CascadeCount(), "distinct", sheet.DistinctStyles()
    mut l2 := els.ref(3)
    l2.focused = true
    l2.focus_visible = true
    l2.pressed = true
    _r := sheet.Restyle(els, 3)
    println "focus", css.ValueText(sheet.Style(3), "outline-style"), css.ValueText(sheet.Style(3), "color")
    mut bare := css.EmptySheet()
    defer bare.Free()
    println "empty", bare.RuleCount(), "defaults added", bare.AddDefaults() > 0
    ua := css.DefaultCss()
    println "default css bytes", ua.len() > 1000, css.TagOf("ordered list")
    mem.Free(ua as void*)
    println "media", env.width, env.height, env.dark, env.reduced_motion, env.hover, env.fine_pointer, env.dir, env.lang, "[" + link.id + "]", "[" + link.classes + "]", "[" + link.base + "]"
    repeat els.len() in i:
        mut x := els.ref(i)
        println i, x.attr_names.len(), x.attr_values.len(), x.media_conditions.len(), x.media_declarations.len()
        x.Free()
    end
    els.free()
end
Outputrules true css rules 2 tag a link 1 true distinct 5 elements 4 p rgb(51, 65, 85) 0px 8px card 12px 16px root block same style true var 12px matches true hovered true true restyled 3 after hover none cascades 6 distinct 6 focus solid rgb(128, 0, 128) empty 0 defaults added true default css bytes true ol media 800 600 false false true true ltr en [] [] [] 0 0 0 0 0 1 0 0 1 1 2 1 1 0 0 3 1 1 0 0

Element

struct Element
What the runtime knows about one element: its page key, tag, id, classes, attributes, parent, the declarations the generator emits for it and its interaction state.
NameTypeDescription
kindstr = "box"The page element key, such as paragraph.
tagstr = "div"The HTML tag that type selectors match.
idstr = ""The id.
classesstr = ""Class names separated by spaces.
parentint = -1Index of the parent, or -1 for the page.
basestr = ""The element's own declarations; they take part in the cascade like a class rule written after the global rules.
inline_stylestr = ""The element's style attribute. It wins over every author rule whatever its specificity, like an inline style in a browser; only !important author rules beat it.
hoverstr = ""Declarations for :hover.
focusstr = ""Declarations for :focus.
activestr = ""Declarations for :active.
hoveredbool = falseWhether the element matches :hover.
focusedbool = falseWhether it has focus.
focus_visiblebool = falseWhether the focus should show a ring (keyboard focus); also counts as focused.
pressedbool = falseWhether it matches :active.
attr_namesVectorAttribute names, for attribute selectors and pseudo-classes such as :checked.
attr_valuesVectorAttribute values, in the same order.
media_conditionsVectorMedia conditions of the element's media children.
media_declarationsVectorDeclarations for each media condition, in the same order.
decl_baseint = -1Id of the element's own declaration list in the sheet's compiled program, or -1 to use base.
decl_hoverint = -1Id of the compiled declaration list for :hover, or -1.
decl_focusint = -1Id of the compiled declaration list for :focus, or -1.
decl_activeint = -1Id of the compiled declaration list for :active, or -1.
decl_dynVectorIds of declaration lists made by DynDecl for style values known only at runtime; they apply after the element's own declarations.

The example for this item is shown with the ones above: gui-css-Sheet.salam

AddAttr

func AddAttr(name: str, value: str)
Adds an attribute.

The example for this item is shown with the ones above: gui-css-Sheet.salam

AddMedia

func AddMedia(condition: str, declarations: str)
Adds declarations that apply while a media condition holds.

The example for this item is shown with the ones above: gui-css-Sheet.salam

HasAttr

func HasAttr(name: str): bool
Whether the element has an attribute.

The example for this item is shown with the ones above: gui-css-Sheet.salam

Free

func Free()
Frees the element's vectors.

The example for this item is shown with the ones above: gui-css-Sheet.salam

Sheet

struct Sheet
A style sheet and the styles computed from it: the user agent defaults, the global and media rules you add, caches of parsed declarations, and the computed style of every element after Compute.

The example for this item is shown with the ones above: gui-css-Sheet.salam

AddRule

func AddRule(selector: str, declarations: str): bool
Adds an author rule: a selector list and a declaration block such as "color: red; margin: 0". Returns false when the selector is not supported, and the rule is then dropped as a browser would drop it.

The example for this item is shown with the ones above: gui-css-Sheet.salam

AddMediaRule

func AddMediaRule(condition: str, selector: str, declarations: str): bool
Adds a rule that applies only while a media condition such as (max-width: 600px) holds for the Env given to Compute.

The example for this item is shown with the ones above: gui-css-Sheet.salam

AddCss

func AddCss(text: str): int
Parses a whole style sheet, including @media blocks, and returns the number of rules added. @supports and @layer blocks are read as if they apply; other at-rules are skipped.

The example for this item is shown with the ones above: gui-css-Sheet.salam

RuleCount

func RuleCount(): int
The number of rules in the sheet, one per selector of each selector list, user agent rules included.

The example for this item is shown with the ones above: gui-css-Sheet.salam

Compute

func Compute(elements &: Vector<Element>, env: Env): int
Computes the style of every element for a viewport and returns the number of distinct styles. Elements must come in document order, each after its parent; elements with identical inputs share one style.

The example for this item is shown with the ones above: gui-css-Sheet.salam

Restyle

func Restyle(elements &: Vector<Element>, index: int): int
After hover, focus, pressed flags or the declarations of one element change, recomputes that element, every element whose state flags changed, and their descendants when an inherited value changed. Returns how many elements were recomputed.

The example for this item is shown with the ones above: gui-css-Sheet.salam

SetColorScheme

func SetColorScheme(elements &: Vector<Element>, dark: bool): int
Switches the sheet to the dark (true) or light colour scheme after the operating system changed it, and restyles only what depends on it: elements whose rules use light-dark(), a system colour, color-scheme or var(), elements matched by a prefers-color-scheme rule whose result changed, and the descendants of every element whose style changed. Returns how many elements were computed again, 0 when the scheme did not change.

The example for this item is shown with the ones above: gui-css-typed.salam

Count

func Count(): int
The number of elements in the last Compute.

The example for this item is shown with the ones above: gui-css-Sheet.salam

Style

func Style(index: int): ComputedStyle
The computed style of an element. Its vectors are owned by the sheet: read them, do not free them, and do not keep them after the next Compute.

The example for this item is shown with the ones above: gui-css-Sheet.salam

RootStyle

func RootStyle(): ComputedStyle
The computed style of the implicit html root that holds the page; :root rules and custom properties set there reach every element.

The example for this item is shown with the ones above: gui-css-Sheet.salam

StyleId

func StyleId(index: int): int
The index of an element's style among the distinct styles; two elements with the same id have the same computed style. -1 before Compute.

The example for this item is shown with the ones above: gui-css-Sheet.salam

DistinctStyles

func DistinctStyles(): int
The number of distinct computed styles kept by the sheet.

The example for this item is shown with the ones above: gui-css-Sheet.salam

CascadeCount

func CascadeCount(): int
How many times the cascade ran since the last Compute; shared styles and cache hits do not count.

The example for this item is shown with the ones above: gui-css-Sheet.salam

Var

func Var(index: int, name: str): str
The value of a custom property such as --gap on an element, with nested var() resolved, or an empty string. The caller frees the result.

The example for this item is shown with the ones above: gui-css-Sheet.salam

Matches

func Matches(selector: str, elements &: Vector<Element>, index: int): bool
Whether a selector list matches an element of the vector.

The example for this item is shown with the ones above: gui-css-Sheet.salam

Free

func Free()
Releases the rules, caches and computed styles.

The example for this item is shown with the ones above: gui-css-Sheet.salam

AddDefaults

func AddDefaults(): int
Adds the user agent style sheet (the browser defaults) to an empty sheet and returns the number of rules and declaration lists added. NewSheet already does this.

The example for this item is shown with the ones above: gui-css-Sheet.salam

AddProgram

func AddProgram(p: Program): int
Adds the rules and declaration lists of a compiled Program. The first program added is the one that element decl_* ids refer to. Calling it again with the same program adds only what the program gained since, such as lists made by DynDecl, and returns how many rules and lists were added.

The example for this item is shown with the ones above: gui-css-Program.salam

Functions

Kw

func Kw(text: str): Piece
A keyword piece, such as auto or solid.

The example for this item is shown with the ones above: gui-css-Program.salam

KwAs

func KwAs(text: str, raw: str): Piece
A keyword piece that keeps the spelling it was written with, used for font family names.

The example for this item is shown with the ones above: gui-css-Program.salam

Num

func Num(value: f64): Piece
A number piece written with a fraction, such as 1.5.

The example for this item is shown with the ones above: gui-css-Program.salam

Int

func Int(value: f64): Piece
A number piece written as an integer, such as 2; some properties accept only integers.

The example for this item is shown with the ones above: gui-css-Program.salam

Dim

func Dim(value: f64, unit: str): Piece
A number with a unit, such as 12px or 1.5em.

The example for this item is shown with the ones above: gui-css-Program.salam

Pct

func Pct(value: f64): Piece
A percentage piece.

The example for this item is shown with the ones above: gui-css-Program.salam

Hash

func Hash(text: str): Piece
A hash piece such as a hex colour, without the #.

The example for this item is shown with the ones above: gui-css-Program.salam

Str

func Str(text: str): Piece
A quoted string piece.

The example for this item is shown with the ones above: gui-css-Program.salam

Url

func Url(text: str): Piece
A url() piece with its address.

The example for this item is shown with the ones above: gui-css-Program.salam

Fn

func Fn(name: str): Piece
Opens a function such as calc or rgba; an empty name opens plain parentheses. Close it with Close.

The example for this item is shown with the ones above: gui-css-Program.salam

Close

func Close(): Piece
Closes the innermost open function or parentheses.

The example for this item is shown with the ones above: gui-css-Program.salam

Comma

func Comma(): Piece
A comma piece.

The example for this item is shown with the ones above: gui-css-Program.salam

Delim

func Delim(code: int, space: bool): Piece
A delimiter character piece such as /, + or :, and whether white space came before it.

The example for this item is shown with the ones above: gui-css-Program.salam

NewProgram

func NewProgram(): Program
A new, empty style program.

The example for this item is shown with the ones above: gui-css-Program.salam

CompileDecls

func CompileDecls(p &: Program, text: str): int
Compiles a declaration list such as "padding: 20px; border-radius: 8px" and returns its id, or -1 when nothing in it is valid. The same text always gives the same id.

The example for this item is shown with the ones above: gui-css-Program.salam

CompileRule

func CompileRule(p &: Program, selector: str, decls: str, media: str): bool
Compiles a global rule: a selector list, its declarations and a media condition (an empty string for none). Returns false when the selector is not supported.

The example for this item is shown with the ones above: gui-css-Program.salam

CompileCss

func CompileCss(p &: Program, text: str): int
Compiles a whole style sheet, @media blocks included, and returns the number of rules read.

The example for this item is shown with the ones above: gui-css-Program.salam

ProgramErrors

func ProgramErrors(p: Program): int
The number of problems found while compiling: unknown properties, invalid values and unsupported selectors.

The example for this item is shown with the ones above: gui-css-Program.salam

ProgramError

func ProgramError(p: Program, index: int): str
The text of a problem found while compiling. The caller frees it.

The example for this item is shown with the ones above: gui-css-Program.salam

ProgramSource

func ProgramSource(p: Program, fn_name: str, css_pkg: str): str
Salam source text of a function with the given name that rebuilds the program from literals, with the given package qualifier (css, an empty string inside this package, or the Persian package name, which also switches the names to Persian). Keywords are English. The caller frees it.

The example for this item is shown with the ones above: gui-css-Program.salam

SheetFromProgram

func SheetFromProgram(p: Program): Sheet
A sheet with the user agent defaults and the program's rules, ready for elements that use decl_* ids.

The example for this item is shown with the ones above: gui-css-Program.salam

DynDecl

func DynDecl(p &: Program, prop: str, value: str): int
Compiles one property value that is known only at runtime and returns a declaration list id for decl_dyn, or -1 when the value is invalid. Each distinct value is parsed once. Call Sheet.AddProgram before computing so the sheet sees the new list.

The example for this item is shown with the ones above: gui-css-Program.salam

NewSheet

func NewSheet(): Sheet
A sheet that starts with the user agent defaults, modelled on Chromium's html.css and checked against Chromium.

The example for this item is shown with the ones above: gui-css-Sheet.salam

EmptySheet

func EmptySheet(): Sheet
A sheet without user agent defaults, for tests or for a page that brings all of its own styles.

The example for this item is shown with the ones above: gui-css-Sheet.salam

DefaultCss

func DefaultCss(): str
The text of the user agent style sheet. The caller frees it.

The example for this item is shown with the ones above: gui-css-Sheet.salam

TagOf

func TagOf(kind: str): str
The HTML tag the web generator uses for a page element key, such as p for paragraph and div for box. Type selectors match these tags. The caller frees the result.

The example for this item is shown with the ones above: gui-css-Sheet.salam

NewElement

func NewElement(kind: str, parent: int): Element
A new element description for a page element key and a parent index (-1 for the page itself), with its tag filled in.

The example for this item is shown with the ones above: gui-css-Sheet.salam

HoverChain

func HoverChain(elements &: Vector<Element>, target: int): int
Marks an element and its ancestors as hovered and clears the flag everywhere else, as a browser does when the pointer moves. Returns the first element whose flag changed, to pass to Restyle, or -1.

The example for this item is shown with the ones above: gui-css-Sheet.salam

ToBox

func ToBox(cs: ComputedStyle): cssbox.Style
The layout part of a computed style as a gui.cssbox style. A length that mixes a percentage with pixels, such as calc(100% - 2em), cannot be expressed there; use ToBoxIn when NeedsBasis says so.

The example for this item is shown with the ones above: gui-css-values.salam

NeedsBasis

func NeedsBasis(cs: ComputedStyle): bool
Whether a layout length of the style mixes a percentage with pixels, so the containing block size is needed to convert it.

The example for this item is shown with the ones above: gui-css-values.salam

ToBoxIn

func ToBoxIn(cs: ComputedStyle, cb_width: f64, cb_height: f64): cssbox.Style
Like ToBox, but resolves mixed lengths against a containing block of the given width and height, the way layout would.

The example for this item is shown with the ones above: gui-css-values.salam

Resolve

func Resolve(l: Len, basis: f64): f64
A length in pixels, with percentages taken of the basis and calc(), min(), max() and clamp() evaluated.

The example for this item is shown with the ones above: gui-css-values.salam

ParseColor

func ParseColor(text: str, out &: Color): bool
Parses a CSS colour: hex with 3, 4, 6 or 8 digits, rgb(), rgba(), hsl(), hsla(), hwb() in comma or space syntax, light-dark(), named and system colours and transparent. Returns false when the text is not a colour.

The example for this item is shown with the ones above: gui-css-values.salam

ColorText

func ColorText(c: Color): str
A colour as rgb(r, g, b) or rgba(r, g, b, a), the way a browser reports computed colours. The caller frees it.

The example for this item is shown with the ones above: gui-css-values.salam

LenText

func LenText(l: Len): str
A length as CSS text: 16px, 50%, calc(50% - 10px), auto and so on. The caller frees it.

The example for this item is shown with the ones above: gui-css-values.salam

ParseDeclarations

func ParseDeclarations(text: str): Vector<Declaration>
Parses a declaration block and returns its declarations with shorthands expanded to longhands and invalid ones dropped. Free the result with FreeDeclarations.

The example for this item is shown with the ones above: gui-css-values.salam

FreeDeclarations

func FreeDeclarations(list &: Vector<Declaration>)
Frees a vector returned by ParseDeclarations.

The example for this item is shown with the ones above: gui-css-values.salam

SelectorSpecificity

func SelectorSpecificity(selector: str): Specificity
The specificity of a selector list (the highest of its selectors); all fields are -1 when the selector is not supported.

The example for this item is shown with the ones above: gui-css-values.salam

MediaMatches

func MediaMatches(condition: str, env: Env): bool
Whether a media query list holds for an environment: width, height and their min and max forms and range syntax, aspect ratio, orientation, colour scheme, reduced motion, hover and pointer, joined with and, or, not and commas.

The example for this item is shown with the ones above: gui-css-values.salam

EasingAt

func EasingAt(t: Timing, x: f64): f64
The output of a timing function for an input progress between 0 and 1, for running transitions.

The example for this item is shown with the ones above: gui-css-values.salam

TransformMatrix

func TransformMatrix(cs: ComputedStyle, width: f64, height: f64): Matrix
The 2D matrix of an element's translate, rotate, scale and transform for a border box of the given size, around its transform-origin.

The example for this item is shown with the ones above: gui-css-values.salam

ValueText

func ValueText(cs: ComputedStyle, property: str): str
A computed value as the CSS text a browser's getComputedStyle gives, for a property name such as margin-top; empty for properties the package does not keep. The caller frees it.

The example for this item is shown with the ones above: gui-css-values.salam

UsedRadii

func UsedRadii(cs: ComputedStyle, width: f64, height: f64): Radii
The corner radii in pixels for a border box of the given size, scaled down together when adjacent radii would overlap, as CSS requires.

The example for this item is shown with the ones above: gui-css-values.salam

FontFamilies

func FontFamilies(cs: ComputedStyle): Vector<str>
The font families of a style in order of preference. The caller frees the vector.

The example for this item is shown with the ones above: gui-css-values.salam

KeywordId

func KeywordId(name: str): int
The stable index of a keyword, unit or function name (flex, px, calc) in the name table, or -1 for a name that is not in it. Names are only ever added at the end.

The example for this item is shown with the ones above: gui-css-typed.salam

KeywordName

func KeywordName(id: int): str
The name at an index of the name table, or an empty string. The caller frees it.

The example for this item is shown with the ones above: gui-css-typed.salam

PropertyId

func PropertyId(name: str): int
The stable integer id of a property name such as margin-top, as used by AddTyped, or -1. Longhands are 0 to 121, shorthands start at 200 and logical properties at 300; new properties are only ever added at the end.

The example for this item is shown with the ones above: gui-css-typed.salam

PropertyName

func PropertyName(id: int): str
The name of a property id. The caller frees it.

The example for this item is shown with the ones above: gui-css-typed.salam

KwId

func KwId(id: int): Piece
A keyword piece given by its name table index.

The example for this item is shown with the ones above: gui-css-typed.salam

DimId

func DimId(value: f64, unit: int): Piece
A number with a unit given by its name table index, such as 1.5 and the index of em.

The example for this item is shown with the ones above: gui-css-typed.salam

FnId

func FnId(id: int): Piece
Opens a function given by its name table index, such as calc or linear-gradient. Close it with Close.

The example for this item is shown with the ones above: gui-css-typed.salam

ColorValue

func ColorValue(light: i64, dark: i64, flags: int): Piece
A colour resolved at compile time: the straight RGBA value 0xRRGGBBAA for the light and the dark scheme and flags (1 when the two differ, 2 when it was written in a syntax newer than hex, named, rgb(), hsl() and hwb(), which makes gradients interpolate in Oklab).

The example for this item is shown with the ones above: gui-css-typed.salam

GradientStops

func GradientStops(l: BgLayer, length: f64): Vector<ColorStop>
Resolves a gradient layer's stops for a gradient line of length pixels (360 for a conic gradient): positions in calc(), missing positions and out of order positions are fixed up as CSS says, colour hints are replaced by nine stops the way Chromium does, and segments in a space other than sRGB are split into short pieces mixed in that space. Each returned stop has pos.px set; free the vector.

The example for this item is shown with the ones above: gui-css-BorderImage.salam

MixColors

func MixColors(start: Color, finish: Color, amount: f64): Color
Mixes two colours with premultiplied alpha, the way a browser interpolates a colour transition: in sRGB when both colours are legacy and in Oklab otherwise, as CSS Color 4 says. 0 gives the first colour and 1 the second.

The example for this item is shown with the ones above: gui-css-typed.salam