hypersig_style クレートの hypersig::style
標準の CSS プロパティはすべてメソッドで、キーワードはすべてバリアントです。プロパティの打ち間違いや型の違う値はコンパイルエラーになり、宣言 1 つが 1 つのクラスになります。
プロパティ、そのキーワード、擬似クラス、名前付きの色は MDN の CSS データから作るので、メソッドは標準に沿います。
Panda CSS や Tailwind CSS と同じく、宣言 1 つが 1 つのクラスになり、ページは要素が使うルールだけを書き出します。
css_when と css_match はページのシグナルに合わせてスタイルを切り替えます。差分には足す要素のルールも含まれます。
色見本は 1 つのトークンを読み、bind_token がラジオグループのシグナルからそのトークンを設定します。詳しくは トークンとテーマ で説明します。
実行結果
use hypersig::html::div;
use hypersig::style::pattern::{stack, wrap};
use hypersig::style::value::{Color, px, rem};
use hypersig::style::{Style, Token};
use hypersig::{Page, Signals};
use hypersig_ui::{ButtonSize, ButtonVariant, button, radio_group, token};
use serde::{Deserialize, Serialize};
#[derive(Signals, Serialize, Deserialize)]
pub struct Palette {
accent: String,
}
pub fn page() -> Page<Palette> {
let accent = Token::new("accent-demo", Color::hex(0x0025_63eb));
let swatch = Style::new()
.width(rem(3))
.height(rem(3))
.border_radius(px(8))
.background_color(accent.var());
Page::new(
"パレット",
Palette {
accent: "#2563eb".into(),
},
)
.child(
div()
.css(stack(rem(1)))
.bind_token(&accent, Palette::accent())
.child(radio_group(
"アクセント",
Palette::accent(),
[
(
"#2563eb".to_owned(),
"青",
),
(
"#16a34a".to_owned(),
"緑",
),
(
"#e11d48".to_owned(),
"ローズ",
),
],
))
.child(
div()
.css(wrap(rem(0.75)))
.child(div().css(swatch.clone()))
.child(div().css(swatch.border_radius(px(999))))
.child(
button(ButtonVariant::Default, ButtonSize::Default)
// The button reads `primary`, which takes the accent here.
.css(Style::new().token(&token::primary(), accent.var()))
.text("アクセントのボタン"),
),
),
)
}hypersig のフレームワークのベンチマーク にある 2000 件の TodoMVC のページを、6 通りのやり方でスタイルし、同じマークアップで hypersig に描かせたものです。違うのはクラス名と CSS だけです。Apple M4 Max の Chrome 155 で、CPU を 4 倍に減速して測りました。ブラウザの値は 5 回、サーバーで描く時間は 50 回の中央値です。
| hypersig | Tailwind CSS | Panda CSS | StyleX | vanilla-extract | 手書きの CSS | |
|---|---|---|---|---|---|---|
| CSS(gzip) | 1.0 KB | 1.6 KB | 1.0 KB | 1.0 KB | 0.6 KB | 0.8 KB |
| CSS を除いた HTML(gzip) | 30.2 KB | 29.1 KB | 26.9 KB | 26.8 KB | 27.6 KB | 27.3 KB |
| 送る合計(gzip) | 31.5 KB | 30.7 KB | 27.8 KB | 27.8 KB | 28.2 KB | 28.1 KB |
| CSS のビルド | なし | 268 ms | 574 ms | 182 ms | 74 ms | 3.1 ms |
| サーバーで描く時間 | 1.7 ms | 1.5 ms | 1.4 ms | 1.4 ms | 0.8 ms | 0.8 ms |
| First Contentful Paint | 136 ms | 140 ms | 136 ms | 144 ms | 140 ms | 140 ms |
| 読み込み時のスタイル計算とレイアウト | 76 ms | 74 ms | 73 ms | 81 ms | 67 ms | 68 ms |
| 2000 件を完了にする時間 | 27 ms | 37 ms | 26 ms | 27 ms | 24 ms | 24 ms |
| hypersig が不利な点 | 理由 |
|---|---|
| HTML の大きさ | クラス名を宣言だけから作るので長くなります。名前は条件、プロパティの正式な名前、値をつないだ font-size_24px のような形で、空白など英数字と .、#、%、- 以外の文字を含む値は 16 桁のハッシュになります。サーバーのパッチはページにあるクラスを知らずに要素を描くので、同じ宣言はいつ描いても同じ名前になる必要があります |
| サーバーで描く時間 | Page::render がその長い名前を項目ごとに書き出します。gzip 前の HTML は hypersig が 1.21 MB、Panda CSS が 0.88 MB で、描く時間も同じ順に長くなります |
ページと計測の仕組みは bench/style にあります。
このクレートは hypersig::style から使い、El は css で Style を受け取ります。hypersig_ui のコンポーネントもこれでスタイルを付けています。