本页内容
普通 CSS 和 CSS Modules 可以按项目需要长期与 Master CSS 共存。将迁移视为一次整理,不必把每条声明都改成类。
将重复的、用于视觉呈现且适合由标记管理的样式移到 Master CSS 类中。全局重置、第三方样式、复杂选择器、生成的 CSS 和难读的一次性规则继续放在普通 CSS 中。
#迁移策略
选择一个能检查原始 CSS 和渲染状态的小组件。按照共用迁移流程建立基线并检查每批工作;本指南重点判断哪些声明适合放在标记里,哪些局部 CSS 契约应该保留。
合适的首批工作具有稳定的视觉声明,不涉及第三方选择器。如果局部类名是 API、需要选中内部结构,或者替换会使复杂选择器散落到各调用处,就保留模块。
改变编写方式,保留结果
比较声明与计算结果。令牌名称相似还不够,值、配色和交互状态都必须匹配。
文字说明
- 从值开始. CSS 规则提供 1rem 间距、1.5rem 内边距和 0.5rem 圆角。
- 匹配预设. gap-md、p-lg、r-lg 提供相同值,两个版本使用相同表面和文本角色。
- 保留结果. 卡片布局、内容和颜色保持不变,只改变样式决策的编写位置。
#在现有 CSS 旁加入 Master CSS
Master CSS 为新增或已转换标记生成规则时,继续加载现有 CSS 文件。删除局部规则前先检查层叠:未分层的旧声明优先于普通分层工具类,即使 Master CSS 后导入也一样。因此,同一元素同时保留两种选择器,可能掩盖转换是否有效。
@import "@master/css";默认源文件发现足以满足多数项目。只有迁移需要明确扫描范围,或类名未以完整字符串出现在源码中时,才添加 @source、@source not、@safelist 或 @blocklist。
大量转换文件前,先根据渲染模式决定使用静态、运行时还是渐进式渲染。
#将局部 CSS 转为标记中的类
当类名列表比独立选择器更容易审查时,将局部视觉声明移到标记。此例已使用安装预设中的共享表面和文本角色,转换时保持不变。
.card { display: grid; gap: 1rem; padding: 1.5rem; border-radius: .5rem; background: var(--color-surface-raised); color: var(--color-text-body);}export function Card({ children }: { children: React.ReactNode }) { return ( <section className="grid gap-md p-lg r-lg bg-surface-raised fg-text-body"> {children} </section> )}用两种样式方式创建相同卡片
值代表产品决策时,优先使用 bg-surface-card、p-card 或 r-card 这类具名主题令牌。如果 CSS 属性本身比新的抽象更清楚,则使用 (scroll-margin-top:4rem) 这类直接的原生声明类。
#当 CSS Modules 是组件 API 时保留
组件公开稳定的局部类名、需要选中内部结构,或在局部变体中使用项目令牌时,CSS Modules 依然有用。
Vite、Next.js 和 Webpack 会自动为局部样式表提供项目主题定义。原生声明会输出所需变量,不必再次导入应用的 CSS 输出。
.button { display: inline-flex; align-items: center; justify-content: center; border-radius: var(--radius-md); gap: var(--spacing-xs); padding-inline: var(--spacing-md); background-color: var(--color-blue-60); color: oklch(100% 0 none); min-height: 2.5rem;}.button:disabled { opacity: 0.5; pointer-events: none;}import styles from './Button.module.css'export function Button(props: React.ButtonHTMLAttributes<HTMLButtonElement>) { const { className, type = 'button', ...buttonProps } = props return <button className={[styles.button, className].filter(Boolean).join(' ')} type={type} {...buttonProps} />}如果移除模块会迫使太多调用处同时修改,就使用此模式。以后局部类不再有价值时,再移除模块。
上方模块未分层,因此普通声明优先于通过 className 传入的分层工具类。若调用方需要使用工具类覆盖组件默认值,请将默认值放进 @layer components,并验证层叠结果。
该包装组件默认使用 type="button";提交表单时传入 type="submit"。采用时保留既有组件的 ref 转发和事件契约。
#将共享值移入 @theme
大规模转换类名之前,通常先把项目拥有的自定义属性放入 @theme,让标记使用令牌名称而非硬编码值。
@import "@master/css";@theme { --color-surface-card: var(--color-surface-raised); --color-body: var(--color-text-body); --spacing-card: 1.5rem; --radius-card: .5rem;}<article class="grid r-card fg-body grid-cols(3)@md bg-surface-card p-card"> ...</article>由运行时管理、组件私有或刻意放在设计系统之外的值,继续使用普通 CSS 自定义属性。
<div className="(width:var(--progress)) bg-blue-60" style={{ '--progress': `${value}%` } as React.CSSProperties} />#验证迁移
每批工作都要同时检查代码和 UI。
- 运行项目的格式化工具、lint、类型检查、测试和生产构建。
- 使用代码检查验证 Master CSS 类字符串。
- 比较迁移后页面在明暗主题、响应式断点、悬停和焦点状态下的表现。
- 如果选择器、动画和第三方输出改成类字符串后更难理解,则保留 CSS。
- 确认没有组件或页面依赖旧 CSS 后,才将其删除。

