Skip to main content
Ladybird’s CSS implementation provides comprehensive support for modern CSS features including parsing, property handling, selectors, and the cascade. The implementation is designed to closely follow CSS specifications with automatic code generation from JSON definitions.

Architecture overview

The CSS engine is organized into several interconnected systems:

Parser

Tokenization and parsing of CSS stylesheets

Properties

Property definitions and value handling

Selectors

Element matching and specificity

Cascade

Style resolution and inheritance

CSS parsing

The CSS parser (CSS/Parser/) converts text into structured data:

Tokenization

The tokenizer (Parser/Tokenizer.h) breaks CSS into tokens:
Token types:
  • Identifiers: Property names, keywords
  • Functions: rgb(), calc(), var()
  • Strings: Text in quotes
  • Numbers: With or without units
  • Delimiters: :, ;, ,, {, }
  • At-keywords: @media, @keyframes, @font-face

Component values

Parsed CSS is represented as component values (Parser/ComponentValue.h):

Parser structure

The main parser (Parser/Parser.h) handles CSS grammar:
The parser follows the CSS Syntax Module specification, using a token stream and component value representation that matches the spec’s algorithms.

Property system

CSS properties are defined in JSON files and generated into C++ code.

Properties.json

The central property definition file (CSS/Properties.json) contains metadata for all CSS properties:
Property metadata fields:

Generated files

From Properties.json, the build system generates:
  • PropertyID.h/cpp: Enum of all properties
  • GeneratedCSSStyleProperties.h/cpp: Property metadata functions
  • GeneratedCSSStyleProperties.idl: JavaScript bindings
When adding a new CSS property, you only need to edit Properties.json. The C++ code and bindings are generated automatically during the build.

Property parsing

Custom property parsing goes in CSS/Parser/PropertyParsing.cpp:
Many properties are parsed automatically from their Properties.json definition. Custom parsing is only needed for complex grammars.

CSS values

CSS values are represented by StyleValue subclasses (CSS/StyleValues/):

Value types

Common value types:
  • Keywords: auto, none, inherit, initial
  • Lengths: Pixels, ems, percentages
  • Colors: Named, hex, rgb(), hsl()
  • Images: url(), gradients
  • Calculations: calc(), min(), max(), clamp()
  • Lists: Space or comma separated values

Computed values

Values go through computation to resolve relative units:

Selectors

Selectors (CSS/Selector.h) determine which elements styles apply to:

Selector specificity

Specificity determines which rules win when multiple match:
  • ID selectors: (1, 0, 0) - #header
  • Class selectors: (0, 1, 0) - .button, [type="text"], :hover
  • Type selectors: (0, 0, 1) - div, span, ::before

Pseudo-classes

Defined in CSS/PseudoClasses.json:
Generated into:

Pseudo-elements

Defined in CSS/PseudoElements.json:
Pseudo-elements create additional boxes:
  • ::before - Insert content before element
  • ::after - Insert content after element
  • ::first-line - Style first line of text
  • ::first-letter - Style first letter
  • ::selection - Style selected text

The cascade

The cascade determines the final computed style for each element:

Cascade algorithm

  1. Collect declarations: Gather all matching rules
  2. Sort by origin and importance:
    • User-agent important declarations
    • User important declarations
    • Author important declarations
    • Author normal declarations
    • User normal declarations
    • User-agent normal declarations
  3. Sort by specificity: Higher specificity wins
  4. Sort by order: Later declarations win

Style inheritance

Inherited properties (Properties.json with "inherited": true) automatically cascade from parent to child:
Commonly inherited:
  • color, font-family, font-size
  • line-height, text-align
  • visibility, cursor
Not inherited:
  • width, height, margin, padding
  • border, background, position
  • display, overflow

Keywords and enums

Keywords.json

All CSS keywords are defined in CSS/Keywords.json:
Generated into:

Enums.json

Grouped keyword sets become enums (CSS/Enums.json):
Generated into:

Adding or modifying properties

As documented in Documentation/CSSProperties.md, adding a CSS property involves:

1. Update JSON data

Edit CSS/Properties.json:

2. Add custom parsing (if needed)

Most properties parse automatically. For complex ones, add to CSS/Parser/PropertyParsing.cpp:

3. Add computed value getter

In CSS/ComputedValues.h:

4. Use the property

In layout or painting code:
The build system automatically regenerates C++ code from JSON files. No manual enum editing needed!

Media queries

Media features are defined in CSS/MediaFeatures.json:
Media queries enable responsive design:

At-rules

At-rules like @font-face, @media, @keyframes are defined in CSS/Descriptors.json:

Transform functions

CSS transforms are defined in CSS/TransformFunctions.json:

Math functions

CSS math functions (CSS/MathFunctions.json):

Units

All CSS units are defined in CSS/Units.json:

Quirks mode

CSS quirks mode provides compatibility with old browsers:
  • Hashless hex colors: color: fff instead of #fff
  • Unitless lengths: width: 100 instead of 100px
Quirks mode is for compatibility only. New content should always use standards mode with a proper DOCTYPE.

LibWeb

Overall rendering engine architecture

DOM

Document structure and elements

Layout

How computed styles become visual boxes