7.1 样式系统总览
> **本节目标**:了解 RML 样式系统的全貌——样式来源、加载机制、作用域、与 GPUI 的关系。
7.1.1 默认样式层级(defaults-first)
开箱 UI 按以下优先级叠加,**应用 CSS 位于最末,仅作可选覆盖**:
| 层级 | 来源 | 示例 | |------|------|------| | L1 | gpui-component `Theme` | `font_size`(14px demo)、`rem`、颜色 token | | L2 | `rml_ui` Shell 组件 | `MenuBar` 按钮间距、`ActivityBar` 面板背景、`TabWindow` bottom slot | | L3 | engine 语义标签 | `h2` 18px、`p` 次要文字 + `--text-muted` | | L4 | 应用 CSS / 主题变量 | `assets/styles.css`、`assets/themes/*.css` |
Demo 在 `Startup::on_launch` 中设置 `Theme.font_size = 14px`;Shell 控件(Menu、StatusBar、Tree)无需 CSS class 即可呈现简洁外观。
7.1.2 样式的来源
RML 的样式来自三个层次:
┌─────────────────────────────────────────────┐
│ RML 样式系统 │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ 内联样式 │ │ 外部样式表 │ │
│ │ style="..." │ │ styles.css │ │
│ └─────────────────┘ └─────────────────┘ │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ 工具类 │ │ 主题变量 │ │
│ │ class="flex" │ │ var(--color) │ │
│ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────┘
内联样式
通过 `style` 属性直接写在元素上:
<div style="background: red; padding: 10px;">
红色背景
</div>
外部样式表
通过 `.css` 文件定义样式,在 `build.rs` 中引入:
/* src/styles/main.css */
.container {
padding: 20px;
background: #f5f5f5;
}
.title {
font-size: 24px;
font-weight: bold;
}
// build.rs
rml::compile_rml()
.with_style("styles/main.css")
.compile()
工具类
预定义的类名,提供常用样式:
<div class="flex flex-col gap-4 p-6">
<h1 class="text-xl font-bold">标题</h1>
</div>
主题变量
通过 CSS 变量实现主题切换:
:root {
--primary-color: #007bff;
--text-color: #333;
}
.button {
background: var(--primary-color);
color: var(--text-color);
}
7.1.3 样式的加载机制
编译时加载
RML 在编译时加载所有样式表,生成高效的样式代码:
// build.rs
fn main() {
rml::compile_rml()
.with_style("styles/reset.css") // 重置样式
.with_style("styles/variables.css") // 主题变量
.with_style("styles/utilities.css") // 工具类
.with_style("styles/components.css") // 组件样式
.compile();
}
加载顺序
样式按声明顺序加载,后加载的样式优先级更高:
1. reset.css ← 基础重置
2. variables.css ← 主题变量
3. utilities.css ← 工具类
4. components.css ← 组件样式
热重载
开发模式下,修改 `.css` 文件会自动触发热重载:
# 修改 styles/main.css 后,应用自动刷新
7.1.4 样式的作用域
全局样式
在 `.css` 文件中定义的样式是全局的:
/* 全局样式,所有 .button 都会应用 */
.button {
padding: 8px 16px;
border-radius: 4px;
}
组件样式
通过命名约定避免冲突:
/* 组件样式,使用组件名作为前缀 */
.user-card {
/* ... */
}
.user-card-header {
/* ... */
}
.user-card-body {
/* ... */
}
内联样式
内联样式优先级最高,只作用于当前元素:
<div style="color: red;">红色文字</div>
7.1.5 样式的优先级
RML 样式优先级从低到高:
1. 全局样式表(按加载顺序)
2. 组件样式表
3. class 属性
4. style 属性(内联样式)
优先级示例
/* 全局样式 */
.button {
color: black;
background: white;
}
/* 组件样式 */
.primary-button {
background: blue;
}
<!-- class 优先级高于全局样式 -->
<button class="button primary-button">按钮</button>
<!-- 颜色:black(全局)
背景:blue(组件样式覆盖全局) -->
<!-- style 优先级最高 -->
<button class="button primary-button" style="background: red;">按钮</button>
<!-- 背景:red(内联样式覆盖一切) -->
7.1.6 样式与 GPUI 的关系
RML 的样式系统建立在 GPUI 之上:
RML 样式(CSS 子集)
↓ 编译
GPUI 样式方法(.bg()、.p()、.text_xl() 等)
↓ 渲染
GPU 渲染
编译示例
<div class="container" style="padding: 10px;">
<h1 class="title">标题</h1>
</div>
编译后等价于:
div()
.class("container") // 应用 .container 的样式
.p(px(10.0)) // 应用内联样式
.child(
div()
.class("title") // 应用 .title 的样式
.child(Label::new("标题"))
)
7.1.7 样式的限制
RML 的样式系统是 CSS 子集,有一些限制:
不支持的 CSS 特性
| 特性 | 说明 | | --------------- | ------------------- | | `@media` 媒体查询 | 部分支持,详见 7.4 | | `@keyframes` 动画 | 通过 GPUI 动画系统实现 | | `:hover` 等伪类 | 通过事件绑定实现 | | `::before` 伪元素 | 不支持 | | `calc()` 函数 | 部分支持 | | CSS Grid | 不支持,使用 Flexbox 替代 |
替代方案
| CSS 特性 | RML 替代方案 | | ---------------- | --------------------- | | `:hover` | `onmouseenter`/`onmouseleave` 事件 | | `:active` | `onmousedown`/`onmouseup` 事件 | | `:focus` | `onfocus`/`onblur` 事件 | | 动画 | GPUI 动画 API | | CSS Grid | Flexbox 嵌套 |
7.1.8 样式的调试
开发者工具
RML 应用支持开发者工具,可以查看元素的样式:
# 启动应用时启用开发者工具
RML_DEV_TOOLS=1 cargo run
样式日志
在代码中打印样式信息:
#[on_loaded]
pub fn on_loaded(&mut self, cx: &mut ViewContext<Self>) {
cx.log_styles(); // 打印当前视图的所有样式
}
7.1.9 样式系统的设计理念
RML 样式系统的设计理念:
1. 熟悉优先
借鉴 CSS 语法,降低学习成本:
/* 与 CSS 几乎相同 */
.container {
padding: 20px;
background: #f5f5f5;
border-radius: 8px;
}
2. 性能优先
编译时处理样式,运行时高效:
- 样式在编译时解析为 GPUI 方法调用 - 避免运行时样式计算 - 支持样式缓存
3. 桌面优先
针对桌面应用优化:
- 使用像素(px)作为主要单位 - 不支持响应式布局(桌面窗口大小固定) - 支持高 DPI 显示
4. 简洁优先
提供工具类简化常用样式:
<!-- 工具类 -->
<div class="flex flex-col gap-4 p-6">
<!-- 等价于 -->
<div style="display: flex; flex-direction: column; gap: 16px; padding: 24px;">
7.1.10 小结
RML 的样式系统:
- **来源**:内联样式、外部样式表、工具类、主题变量 - **加载**:编译时加载,支持热重载 - **作用域**:全局、组件、内联 - **优先级**:全局 < 组件 < class < style - **与 GPUI**:样式编译为 GPUI 方法调用 - **限制**:CSS 子集,部分特性不支持
下一节 → [7.2 CSS 子集与扩展](./css-subset.md)