原生 CSS 裁剪
控制每份样式表中的原生类裁剪和按需生成的关键帧。
本页内容
原生 CSS 裁剪移除未使用的类选择器分支,并使关键帧按需可用。这是样式表策略,与工具类生成分开。优化 CSS 交付说明何时启用;扫描指令定义源与候选筛选。
裁剪指令止于文件边界
此次编译仅使用 local。app.css 启用,cards.css 未启用。导入 cards.css 不会将裁剪指令传入其中。
文字说明
- app.css 包含 @prune native、导入 cards.css,并定义 .local 和 .unused-local。唯一使用的类是 local。
- 其输出保留 .local,移除 .unused-local。
- cards.css 未声明裁剪或保留指令。即使两个类均未使用,默认策略仍保留 .card 和 .unused-card。
- 全项目 pruneNativeCSS 选项可另行让项目文件参与裁剪。@preserve native 在其所属文件内优先。本例单独呈现显式逐文件策略。
原生 CSS 默认保留,即使提供类列表也一样。在集成或样式表 API 中设置 pruneNativeCSS: true,可裁剪项目拥有的源。包 CSS 仍保留,除非其源显式启用裁剪。
@prune native
@prune native;.used { color: red;}.unused { color: blue;}此指令仅对声明文件启用裁剪,不会传递到导入样式表。同文件中的 @preserve native; 优先,即使集成启用全项目裁剪也一样。原生输出开关 preserveNativeCSS: false 是独立选项,无论两个指令如何设置,均抑制原生输出。
@preserve native
Master 管理的样式表若包含不可被原生 CSS 裁剪移除的原生类规则,请用 @preserve native;。
@import "@master/css";@preserve native;.injected-by-payment-widget { color: blue;}样式表仍由 Master CSS 处理。即使扫描源未使用这些类,原生类规则仍保留;常规编译器规范化仍会应用。此策略不会强制将未使用的受管理类加入生成输出,也不代表保留原始 CSS 字节。
同文件中 preserve 优先于 prune
两种情况均启用原生交付。此策略保留原生 CSS,不会将未使用受管理工具类加入安全列表。
文字说明
- @preserve native 与 @prune native 同文件出现时,无论顺序均以保留为准。
- 因此即使没有扫描到 widget 类,原生 .widget 规则仍保留。
- preserveNativeCSS: false 是独立输出开关,可不受两个指令影响而抑制原生交付。
导入图
已解析 CSS 导入保留各自源边界,因此每个文件的策略仅适用于自身。导入方不能为依赖文件启用裁剪。pruneNativeCSS: true 下,项目拥有的依赖文件参与裁剪,除非声明 @preserve native;;包和远程样式不会因为项目导入它们就变为项目拥有。带限定导入保留 media、supports 与 layer 包装。
@prune native;@import "@master/css";@import "./cards.css";@prune native;.card { border: 1px solid rgb(0 0 0 / 12%);}.unused-card { color: red;}扫描源含有 card 时,输出保留 .card 并移除 .unused-card。若 cards.css 没有该指令,两条规则均保留。
根节点作用域
启用设置属于各源文件;筛选使用导入该文件的根节点之使用范围。因此同一份已启用共享文件可在不同根节点下保留不同类。由 JavaScript 或框架路由直接导入的文件,仅当该导入进入 Master CSS 管线时才成为自身根节点。
根节点默认使用全局扫描器范围。根节点导入图任意位置的 @source、@source not、@safelist 和 @blocklist 均可缩小或扩大范围;导入文件中的指令合并到每个导入它的根节点,相对模式则以声明文件为基准解析。
@prune native;@import "@master/css";@source "./page.html";@import "../shared.css";@prune native;@blocklist "debug-*";.shared-card { border: 1px solid rgb(0 0 0 / 12%);}.only-used-in-b { color: blue;}.debug-outline { outline: 1px solid red;}若 app/a/page.html 仅使用 shared-card,a.css 输出保留 .shared-card,并移除 .only-used-in-b 和 .debug-outline。另一根节点 b.css 的页面若使用 only-used-in-b,则从同一共享文件保留该规则。
规则筛选
类选择器规则只要有一条分支中的任一类被使用就会保留;选择器列表中未使用分支则被移除。检查依据是类名而非 DOM 关系:对于 .card .title,找到 card 或 title 任一个就保留分支,因此保留规则仍可能不匹配任何元素。
@prune native;body { margin: 0;}.card,.unused:hover { border: 1px solid rgb(0 0 0 / 12%);}@media (width >= 48rem) { .card .title { font-weight: 700; } .debug-card { outline: 1px solid red; }}使用 card 和 title 时,输出保留 body、.card 与 .card .title,并移除 .unused:hover 和 .debug-card。body、html、:root 这类没有类选择器的规则始终保留。裁剪后变空的 at-rule 块则移除。
裁剪按类使用情况保留分支
保留高亮遵循选择器分支。裁剪检查已使用类名,不检查完整选择器当前是否匹配元素。
文字说明
- 启用 @prune native 且使用 card 时,.card, .unused:hover 仅保留 .card 分支。
- 另一条 .card .title 分支因 card 位于已使用集合而保留,无须同时找到 title。
- 保留不代表 DOM 含有 title 后代。没有类选择器的规则仍会保留。
manifest 引用
保留的原生规则若读取 var(--*) 或指定 manifest 动画名称,会保留项目入口图中对应的主题变量和关键帧。被移除规则不保留任何资源。
@prune native;@import "@master/css";@theme { --color-primary: #175cff;}.notice { color: var(--color-primary);}.unused-notice { color: var(--color-primary);}若仅使用 notice,由于 .notice 被保留,会输出 --color-primary;.unused-notice 则被移除。
包含的类
来自有限外部来源的原生类可用 @safelist 标为已使用,使裁剪保留其规则。它不替代应用在扫描源中编写的类。
@prune native;@safelist "dialog-open dialog-closing";.dialog-open { overflow: hidden;}.dialog-closing { pointer-events: none;}原生关键帧
在原生 CSS 中声明关键帧,并在其所属文件启用基于使用情况的输出:
@prune native;@theme { --animate-reveal: reveal .2s ease-out both;}@keyframes reveal { from { opacity: 0; } to { opacity: 1; }}@safelist keyframes "external-enter" "external-exit";@keyframes external-enter { from { opacity: 0; } to { opacity: 1; }}@keyframes external-exit { from { opacity: 1; } to { opacity: 0; }}关键帧与原生类规则遵循相同文件策略。默认是原生 CSS:在输出中原位、原样保留,Master CSS 绝不再次输出。@prune native; 使该文件的关键帧像令牌一样成为按需定义:它们离开原生输出,改由使用它们的输出与生成 CSS 一起输出。两个指令同时出现时,@preserve native; 优先。策略仅适用于声明文件,不通过导入传递。pruneNativeCSS 选项保留项目拥有文件的范围。包 CSS 仍保留,除非显式启用裁剪。preserveNativeCSS: false 抑制原生交付;按需定义仍在使用处输出。
关键帧使用根节点
动画工具类、原生动画声明、静态动画令牌和关键帧安全列表使用对应定义。分析追踪简写值、animation-name 列表、嵌套变量、回退值、限定作用域的覆盖及传递令牌依赖。已使用定义也会使用帧读取的令牌;原生定义仅提供这些令牌,因为样式表自身交付帧。未解析的动态名称保守使用编译图中所有候选定义,并产生信息诊断。
动画名称可在没有类时保留定义
文件启用 @prune native。关键帧安全列表保留资源,不会启动动画。
文字说明
- 在含 @prune native 的文件中,@safelist keyframes "reveal" 保留匹配的 @keyframes reveal 定义。
- 输出包含关键帧定义,但不会仅因安全列表就生成类或动画声明。
- 仍需其他原生声明或脚本选择动画。没有该使用情况时,单纯保留定义不会产生可见动画效果。
关键帧条件与限制
输出的按需定义包在原声明位置的条件和层规则内,包括带限定导入的层,并位于生成层之后。同一容器内的定义共用一个包装。同名定义保持独立并按声明顺序排列,由浏览器决定胜出的定义。名称会解码且区分大小写。匿名层无法重新进入,因此位于匿名层内或导入匿名层的按需关键帧会导致编译错误;请为层命名或保留文件。帧在原样式表之外输出,因此其中的相对 url() 会导致编译错误;请使用绝对 URL 或保留文件。定义 ID 来自声明文件最近且具有名称的 package.json 及包相对路径,因此同项目从任何检出或安装目录均输出相同 CSS。重命名该包会改变 ID;不在命名包内的文件则回退至绝对路径。
关键帧资源所有权
帧包含原生声明;不支持帧内嵌套指令和 @apply。未使用工具类和混入、已裁剪原生规则及未交付引用样式均不创建使用根节点。@reference 使定义按需可用,但不导入其保留策略或安全列表;含相对 URL 的原生关键帧仍随样式表交付。项目或基础 manifest 的原生关键帧,在不交付它们的样式表中同样按需可用。emitted globals 列出输出以原生或按需方式交付的关键帧,使其他输出不会重复输出。仅由 JavaScript 引入的动画名称,请使用 @safelist keyframes "reveal";。
运行时关键帧生命周期
运行时分别追踪定义 ID 与名称,并将按需定义插入自身样式表。DOM 移除仅在没有原生使用、静态令牌或安全列表继续使用该定义时才释放它。HMR 一同替换定义与 emitted globals;SSR hydration 使用相同 ID 和资源顺序。链接样式表保持常规 CSS,不添加伴随文件或标记。
Native keyframes
@keyframes fade-in { to { opacity: 1; } }生成的 CSS
@keyframes fade-in { to { opacity: 1; }}






