Overview
hypersig::style is typed atomic CSS. A misspelled property name or keyword, or a value of the wrong type, is a compile error. Each declaration becomes one class.
A style is a Rust value
Style has one method per standard CSS property, and per anchor positioning property. The property list, each property's keywords, the pseudo-classes, the pseudo-elements, and the named colors are generated from MDN's CSS data (mdn-data 2.37.2). El::css adds a style to an element.
use hypersig::html::button;
use hypersig::style::Style;
use hypersig::style::value::{Color, Cursor, FontWeight, px, rem};
use hypersig::{Page, Signals};
use serde::{Deserialize, Serialize};
#[derive(Signals, Serialize, Deserialize)]
struct Shop {
count: i32,
}
let buy = button::<Shop>()
.css(
Style::new()
.padding_block(rem(0.5))
.padding_inline(rem(1))
.border_radius(px(6))
.background_color(Color::hex(0x0018_181b))
.color(Color::WHITE)
.font_weight(FontWeight::Number(500.0))
.cursor(Cursor::Pointer),
)
.text("Buy");
let html = Page::new("Shop", Shop { count: 0 }).child(buy).render();
// One class per declaration, named after it, and one rule per class in <head>.
assert!(html.contains("cursor_pointer"));
assert!(html.contains(".cursor_pointer{cursor:pointer}"));A second call to the same property's method under the same conditions replaces the earlier value, as a later declaration does in a CSS rule. merge adds the declarations of another style, and the added declarations override the original ones.
One class per declaration
Each declaration becomes one class, whose name comes from the declaration, such as cursor_pointer or hover:color_crimson. Panda CSS and Tailwind CSS do the same in their atomic CSS. For a value with characters other than letters, digits, ., #, %, and -, the class name uses a hash of the value. Two elements with the same declaration use the same class, so the stylesheet grows with the number of distinct declarations rather than the number of elements.
The page collects the styles its elements use and writes each rule once into <head>. A patch that contains new elements also contains their rules, inserted where a breakpoint value still overrides the base value.
Styles switched by a signal
css_when(style, cond) adds a style while a signal condition holds, and css_match(value, cases) picks one style per value of a signal, like the variants of a Panda CSS recipe. Their rules are in a later cascade layer than those of css, so while switched on they override the element's own declarations for the same property.
| Cascade layer | Holds |
|---|---|
hypersig-tokens | The values a Theme sets on :root |
hypersig-base | The rules of a Global, such as the reset |
hypersig-atoms | The classes of El::css |
hypersig-toggled | The classes of El::css_when and El::css_match |
The layers come in that order, so an element's classes override the global rules, and a switched-on style overrides both. A stylesheet added with Page::style is in no layer and overrides all four layers.