Colors and Backgrounds
wgpu-html supports a broad range of CSS color formats and background properties. Colors are parsed into a typed CssColor enum and resolved to [r, g, b, a] linear sRGB at paint time for GPU consumption.
Color Formats
Hexadecimal
All four CSS hex formats are supported:
color: #f00; /* #rgb → #ff0000 */
color: #f00f; /* #rgba → #ff0000ff */
color: #ff0000; /* #rrggbb */
color: #ff000080; /* #rrggbbaa (50% alpha) */
RGB / RGBA Functions
color: rgb(255, 0, 0);
color: rgb(100%, 0%, 0%);
color: rgba(255, 0, 0, 0.5);
color: rgba(100%, 0%, 0%, 50%);
Components accept integers (0–255), percentages (0%–100%), and bare floats (0.0–255.0). Alpha accepts floats (0.0–1.0) or percentages.
HSL / HSLA Functions
color: hsl(0, 100%, 50%); /* red */
color: hsl(120deg, 100%, 25%); /* green (dark) */
color: hsla(240, 100%, 50%, 0.7); /* semi-transparent blue */
Hue accepts degrees (bare number or deg suffix). Saturation and lightness are percentages.
Named Colors
black, white, red, green, blue, yellow, cyan, aqua,
magenta, fuchsia, gray, grey, lightgray, lightgrey,
darkgray, darkgrey, silver, maroon, olive, lime,
teal, navy, purple, orange, pink
color: orange;
background-color: navy;
border-color: silver;
CSS Color Module Level 4 System Colors
System colors are used primarily in the UA stylesheet for form controls. They are resolved to specific sRGB values at paint time:
background-color: canvas;
color: canvastext;
border-color: buttonborder;
background-color: field;
color: fieldtext;
background-color: buttonface;
color: buttontext;
Full system color list: canvas, canvastext, linktext, visitedtext, activetext, buttonface, buttontext, buttonborder, field, fieldtext, highlight, highlighttext, selecteditem, selecteditemtext, mark, marktext, graytext, accentcolor, accentcolortext.
Special Color Keywords
color: transparent; /* rgba(0, 0, 0, 0) */
color: currentColor; /* resolves to None — no fallback */
Note:
currentColoris parsed asCssColor::CurrentColorbut resolves toNonein the paint pass. Borders without an explicit color are skipped (no fallback tocolororcurrentColor).
background-color
Sets a solid color fill for the element's background:
.box {
background-color: #f0f0f0;
background-color: rgb(240, 240, 240);
background-color: hsl(0, 0%, 94%);
background-color: lightgray;
background-color: transparent; /* no fill */
}
The background color is painted as a quad (or SDF-rounded quad when border-radius is set) clipped to the background-clip box.
background-clip
Controls which box the background extends to:
background-clip: border-box; /* background fills to outer border edge (default) */
background-clip: padding-box; /* background stops at inner border edge (outside padding) */
background-clip: content-box; /* background stops at content edge */
border-box: ┌────────────────────┐
│▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓│ border
│▓┌──────────────────┐│
│▓│ padding + ││
│▓│ content ││
│▓└──────────────────┘│
└────────────────────┘
padding-box: ┌──border─────────────┐
│ ┌──────────────────┐│
│ │▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓││
│ │▓padding + ││
│ │▓content ││
│ │▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓││
│ └──────────────────┘│
└──────────────────────┘
content-box: ┌──border─────────────┐
│ ┌──padding─────────┐│
│ │ ┌──────────────┐││
│ │ │▓▓▓▓▓▓▓▓▓▓▓▓▓▓│││
│ │ │▓content ▓│││
│ │ │▓▓▓▓▓▓▓▓▓▓▓▓▓▓│││
│ │ └──────────────┘││
│ └──────────────────┘│
└──────────────────────┘
When combined with border-radius, the background clip uses concentric inner radii: padding-box radius = max(0, border_radius - border_width), content-box radius = max(0, padding_radius - padding).
background-image
Loads an image from a URL as the element's background:
.hero {
background-image: url("hero.jpg");
background-image: url("https://example.com/bg.png");
background-image: none; /* remove background image */
}
The URL can be:
- A relative or absolute file path
- An HTTP(S) URL
- A
data:URI - Quoted (
url("path")) or unquoted (url(path))
Images are loaded asynchronously by the layout crate, cached with TTL and byte-budget eviction, and rendered through the image pipeline. Supported formats include PNG, JPEG, GIF (including animated), and WebP.
background-repeat
Controls tiling of the background image:
background-repeat: repeat; /* tile both axes (default) */
background-repeat: repeat-x; /* tile horizontally only */
background-repeat: repeat-y; /* tile vertically only */
background-repeat: no-repeat; /* single image, no tiling */
background-size and background-position
Both properties are parsed from CSS and stored as raw strings:
background-size: cover;
background-size: contain;
background-size: 100% auto;
background-size: 200px 150px;
background-position: center;
background-position: top left;
background-position: 50% 50%;
background-position: 10px 20px;
These are consumed by the layout engine from their raw string form. Full structuring for all values is not yet implemented.
sRGB → Linear Color Conversion
The quad pipeline converts sRGB colors to linear space for correct GPU blending. The WGSL shader performs the conversion:
// sRGB to linear (approximate gamma 2.2)
linear = pow(srgb, 2.2);
This ensures that color blending, opacity compositing, and anti-aliasing produce visually correct results on gamma-correct surfaces.
Code Examples
Background with Rounded Clip
.card {
background-color: #ffffff;
border: 1px solid #e0e0e0;
border-radius: 12px;
background-clip: padding-box;
padding: 24px;
}
Tiled Background Pattern
.pattern-bg {
background-color: #f5f5f5;
background-image: url("pattern.png");
background-repeat: repeat;
}
Hero Section
.hero {
background-color: #1a1a2e;
background-image: url("hero-overlay.png");
background-repeat: no-repeat;
color: white;
padding: 80px 24px;
}
System Color Form
input[type="text"] {
background-color: field;
color: fieldtext;
border: 1px solid buttonborder;
padding: 6px 12px;
border-radius: 4px;
}
input[type="text"]:focus {
border-color: highlight;
background-color: field;
}
Rust: Resolving Colors Programmatically
use wgpu_html_models::CssColor;
// Parse a color string
let color = parse_css_color("hsla(200, 80%, 50%, 0.8)");
// Resolve to [r, g, b, a] in linear space
fn resolve_color(c: &CssColor) -> [f32; 4] {
match c {
CssColor::Named(name) => resolve_named_color(name),
CssColor::Hex(h) => resolve_hex_color(h),
CssColor::Rgb(r, g, b) => srgb_to_linear([*r, *g, *b, 255]),
CssColor::Rgba(r, g, b, a) => srgb_to_linear([*r, *g, *b, (*a * 255.0) as u8]),
CssColor::Hsl(h, s, l) => hsl_to_srgb(*h, *s, *l),
CssColor::Hsla(h, s, l, a) => {
let [r, g, b] = hsl_to_srgb(*h, *s, *l);
[r, g, b, *a]
}
CssColor::Transparent => [0.0, 0.0, 0.0, 0.0],
CssColor::CurrentColor => panic!("unresolved currentColor"),
CssColor::Function(_) => [0.0, 0.0, 0.0, 1.0],
}
}