样式与呈现
清晰边界下的样式设计。
可移植声明使用类型化 Style,文档 CSS 使用类名,有限的可移植子集使用经过验证的 Sheet。CSS 层叠、字体和布局仍由渲染宿主负责。
完整替换
style(...) 替换完整的类型化 Style,class(...) 替换完整的空白分隔类名列表。多次调用不会追加或合并。先计算最终值,并包含 row() 或 col() 提供的布局声明。
使用类型化 Style 表达语义声明
Style 为尺寸、flex 布局、溢出、颜色、字体、边框和其他支持的属性提供显式 Rust 类型。缺省字段不输出内联声明;显式默认值仍有实际含义。
typed.rs
use glory::prelude::*;
fn status_panel() -> impl Widget {
let style = Style::new()
.display(Display::Flex)
.flex_direction(FlexDirection::Column)
.width(Length::Percent(100.0))
.max_width(Limit::Px(640.0))
.gap(8.0)
.padding(Edges::all(16.0))
.radius(8.0);
view()
.class("status-panel")
.style(style)
.fill(text().content("Ready"))
}replacement.rs
use glory::prelude::*;
fn panel(active: bool) -> impl Widget {
// Compute each final value once instead of trying to append declarations.
let classes = if active { "panel is-active" } else { "panel" };
let style = Style::new()
.padding(Edges::all(16.0))
.gap(if active { 8.0 } else { 12.0 });
view().class(classes).style(style)
}
fn replacement_pitfall() -> impl Widget {
view()
.class("panel")
.class("panel is-active") // Final classes: panel and is-active.
.style(Style::new().padding(Edges::all(16.0)))
.style(Style::new().gap(8.0)) // The padding declaration is gone.
}通过类名使用外部 CSS
类名将语义节点连接到外部文档 CSS。外部 CSS 不按类型化 Style 解析,因此可使用宿主引擎更广泛的 CSS 语法。可在浏览器文档中提供它,在 SSR Document 中列出它,或通过原生宿主安装;Glory 不会从类名推断共享样式表。
app.css
.profile {
display: flex;
gap: 12px;
padding: 16px;
border: 1px solid #ccd4e0;
}
.profile > .profile-title {
font: 600 1.25rem/1.4 system-ui, sans-serif;
}profile.rs
use glory::prelude::*;
fn profile() -> impl Widget {
view().class("profile").fill(
text()
.class("profile-title")
.content("Ada Lovelace"),
)
}
// With the ssr feature, attach the external document stylesheet.
let document = glory::ssr::Document {
title: "Profile".into(),
stylesheets: vec!["/assets/app.css".into()],
..Default::default()
};
let html = glory::ssr::render_document(profile(), &document)?;解析有界 Sheet
启用 Glory 的 css 特性可解析不可变 Sheet。它接受当前类型化属性、基于类的子代和后代选择器,以及 hover/focus/enabled/disabled/checked 状态。at 规则、ID 和类型选择器、未知声明、不支持的值及超出预算的输入都会被拒绝。它不是完整 CSS 解析器。
sheet.rs
use glory::prelude::*;
use glory::style::{Profile, Sheet};
fn render_panel() -> std::result::Result<String, Box<dyn std::error::Error>> {
let sheet = Sheet::parse(
".panel { display:flex; gap:12px; padding:16px } \
.panel > .title:hover { color:#123456; max-width:none }",
)?;
sheet.check(Profile::HTML)?;
let document = glory::ssr::Document {
title: "Bounded sheet".into(),
sheets: vec![sheet],
..Default::default()
};
let widget = view()
.class("panel")
.fill(text().class("title").content("Portable rules"));
Ok(glory::ssr::render_document(widget, &document)?)
}示例使用 ssr + css:render_document 针对 Profile::HTML 检查并转换每条规则。手动集成时,glory::html::sheet(&sheet, profile) 生成经过验证的 HTML 系列 CSS;支持 CSS 的 Blitz 渲染器使用 set_sheet(&sheet)。安装前会再次检查目标配置。
区分缺省尺寸与无限尺寸
最大尺寸使用 Limit,不使用 Length。Option::None 表示字段缺省,由样式表控制;Some(Limit::None) 显式输出无限上限,移除样式表限制。Length::Auto 用于首选和最小尺寸,不用于 max_width 或 max_height。
limits.rs
use glory::prelude::*;
let absent = Style::new();
let uncapped = Style::new().max_width(Limit::None);
let capped = Style::new().max_width(Limit::Percent(80.0));
assert_eq!(absent.max_width, None); // No inline declaration; CSS can set a cap.
assert_eq!(uncapped.max_width, Some(Limit::None)); // Explicit max-width: none.
assert_eq!(capped.max_width, Some(Limit::Percent(80.0)));
// Preferred and minimum sizes use Length, including Length::Auto.
let automatic = Style::new().width(Length::Auto);
assert_eq!(automatic.width, Some(Length::Auto));检查所选宿主的能力配置
每个渲染器在 App 生命周期内暴露不可变的样式配置。挂载和类型化样式更新会在提交前验证值,并拒绝不支持的属性或单位。Profile::RECORD 接受声明但不执行布局;HTML 和 Blitz 各有真实引擎边界。
profiles.rs
use glory::prelude::*;
fn accepted_by_host(app: &glory::App, style: &Style) -> bool {
style.validate().is_ok()
&& app.style_profile().inline.check(style).is_ok()
}
// App::memory() records typed declarations with Profile::RECORD, but does no layout.
// HTML hosts use Profile::HTML. Blitz exposes its current native profile as
// glory::blitz::STYLE_PROFILE when the blitz feature is enabled.可移植值不保证相同像素
两个宿主接受同一声明,仍可能使用不同字体、文本整形、视口规则和 CSS 引擎。请在每个目标上测试重要布局,不要期待像素完全一致。
使用 Sapid 主题设置组件样式
Sapid 的 Theme、调色板、变体和尺寸提供协调一致的组件样式。先用主题设置控件颜色及状态,再用 Glory 样式或应用样式类处理外围布局。迁移到其他渲染宿主时,请同时核对示例中的样式表配置和具体组件的宿主支持情况。
浏览 Sapid 主题与组件示例 ↗