Theming
Colours as CSS variables
A theme on an HTML screen is what it is on the web: custom properties, a
prefers-color-scheme media query, and a class when the user overrides the system.
Nothing in this crate replaces that, so a stylesheet written for a browser keeps its themes.
Custom properties
samples/theme writes every colour as a var(). A light set is the
default, a dark set applies under prefers-color-scheme: dark, and a class on the
app's root wins over both.
:root, .app.light {
--bg: #ffffff;
--surface: #f3f4f6;
--text: #111827;
--accent: #2563eb;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #111827;
--surface: #1f2937;
--text: #f9fafb;
--accent: #60a5fa;
}
}
.app.dark {
--bg: #111827;
--surface: #1f2937;
--text: #f9fafb;
--accent: #60a5fa;
}
.app { height: 100%; padding: 24px; background-color: var(--bg); color: var(--text); }
Light and dark
HtmlConfig::color_scheme answers prefers-color-scheme. It is
ColorScheme::Light unless you say otherwise.
let dom = HtmlDom::with_config(
theme::app,
HtmlConfig {
stylesheets: vec![theme::STYLE.to_string()],
color_scheme: ColorScheme::Dark,
..HtmlConfig::default()
},
);
With no class on the app, Dark picks the dark set. The test checks every colour
on the page against both sets.
Overriding the system
The toggle button puts light or dark on the root element. That is a
class change and nothing else, so only colours change.
// None follows the system through the media query.
let mut theme = use_signal(|| None::<Theme>);
let class = match theme.cloned() {
None => "app",
Some(Theme::Light) => "app light",
Some(Theme::Dark) => "app dark",
};
rsx! {
div { id: "app", class: "{class}",
button {
id: "theme-toggle",
class: "toggle",
onclick: move |_| {
let next = match theme.cloned() {
Some(Theme::Dark) => Theme::Light,
_ => Theme::Dark,
};
theme.set(Some(next));
},
"Toggle theme"
}
}
}
The test clicks the toggle and checks the layout diff: entries changed, none were added or removed, the order is the same, and every changed entry differs from before in its colours only.
Not yet
- Following the system while running.
planned The colour scheme is fixed when the
HtmlDomis made. The renderer learns of a system change first, so it will pass that change on once it draws HTML screens (#43). - CSS variables as colour roles. planned
On a screen that mixes HTML and widgets, both will follow one theme, with the CSS variables
tied to the widgets' colour roles. The plan already has the seam for it: a
ColourResolvermay replace a computed colour with the role it stands for, so a theme change will not need a new layout. See Mixing the two. - Animated theme changes. planned
A
transition: background-colordoes not play today (#46).