工具类与混入
定义按需生成的工具类、可复用的混入以及使用层叠层的原生样式。
本页内容
@utility 注册按需生成的类。@mixin 为可复用 CSS 主体命名;@apply 在调用处展开它。原生选择器仍为常规 CSS。复用样式说明如何选择形式;本页定义其语法与替换规则。
@utility
在顶层显式声明类形式:
@utility card-layout { display: grid; gap: var(--spacing-md); &:hover { outline: 1px solid currentColor; }}@utility col-gap-(--spacing) { column-gap: var(--spacing);}@utility grid-cols(--cols <integer>) { display: grid; grid-template-columns: repeat(var(--cols), minmax(0, 1fr));}在标记中使用 card-layout、col-gap-sm 和 grid-cols(3)@sm。头部决定定义注册的是固定类、令牌模式还是函数。每种形式仅注册该形式,令牌模式不会同时创建函数调用。添加声明或支持的嵌套规则不会改变注册形式。
工具类名称和令牌前缀不能包含 _,因为 _ 在类中开始后代选择器;此类定义会在源位置报告错误。令牌键可以含 _:它仍是可供 var() 使用的有效变量,但不会生成裸令牌类或补全。混入名称、自定义属性及原生样式表类仍可使用 _。
注册与预设
主题提供令牌,工具类定义决定这些令牌能产生哪些类。导入 "@master/css" 获取完整预设;显式组合样式表时,也可搭配自己的令牌加载 "@master/。
家族索引提供完整令牌与属性映射。固定工具类和直接数值列出各自的注册。它们均使用本页所述的相同定义形式。
令牌模式
模式有一个末尾占位符。参数指定令牌命名空间,固定部分指定类前缀。无类型占位符绑定令牌值:
@utility p-(--spacing) { padding: var(--spacing);}@utility m-(--spacing) { margin: var(--spacing);}@utility fg-(--color) { color: var(--color);}@utility size-(--spacing) { width: var(--spacing); height: var(--spacing);}p-md 绑定 var(--spacing-md);size-md 在两条声明中使用该引用。常规令牌保留由浏览器求值的引用,inline 令牌则将声明值代入一次。未知令牌不会创建类。值模式接受数字和 Unicode 键,包括包含 -- 的键。
<string> 占位符绑定令牌键,可用于显式引用伴随值:
@theme { --text-hero: var(--font-size-5xl); --text-hero--line-height: 1.15; --text-hero--letter-spacing: -.03em;}@utility text-(--text <string>) { font-size: var(ident("--text-" var(--text))); line-height: var(ident("--text-" var(--text) "--line-height"), normal); letter-spacing: var(ident("--text-" var(--text) "--letter-spacing"), normal);}text-hero 绑定字符串 "hero",且必须存在对应的主要令牌。含 -- 的伴随键不创建类;缺少伴随值时使用原有回退值。ident() 静态折叠为常规 CSS 标识符。命名空间来自参数,因此 @utility type-(--text <string>) 使用相同令牌,搭配不同类前缀。令牌占位符不接受默认值或其他类型。
共享前缀可以显式提供多个命名空间:
@utility font-(--font-family) { font-family: var(--font-family);}@utility font-(--font-size) { font-size: var(--font-size);}@utility font-(--font-weight) { font-weight: var(--font-weight);}font-sans、font-sm 和 font-bold 各自选择唯一包含该键的命名空间。键若存在于多个分支,使用时报告 AMBIGUOUS_TOKEN 且不产生 CSS。请改用不同键,或 (font-size:var(--font-size-brand)) 这类原生声明。此规则也适用于字符串键配方和多声明主体。负值与不透明度仅在选定唯一分支后才检查。
固定类优先于模式:保留的是完整类名拼写,而非令牌键。因此即使存在 --text-center,text-center 仍设置 text-align;fg-solid、b-solid/.5 和 -mx-auto 则仍可使用名为 solid 或 auto 的令牌。模式采用最长前缀;所选家族内若没有令牌,就报告错误,不再尝试较短前缀。参数命名空间不同的令牌模式可共用前缀。较后模式完整替换解码后前缀与命名空间均相同的定义,包括参数模式、主体、来源与依赖。静态和函数注册则各自独立替换同形式、同名称的定义。
负值与不透明度适用于直接值子集:一个无类型占位符,以及一条完整值恰为 var(--parameter) 的原生声明。-m-md 将数值间距令牌转为负值;-p-md 无效,因为 padding 不支持负值。fg-red/.5 为颜色令牌应用不透明度,范围为零到一。这些能力不扩展到常规多声明或字符串键配方。
两个匹配的命名空间不会产生两条声明
此自定义主题中两个令牌键均存在。Master CSS 必须先选出唯一命名空间,才会生成类。
文字说明
- 存在 --font-family-brand: monospace 和 --font-size-brand: 2rem 时,font-brand 匹配两个预设 font- 家族。
- 结果为 AMBIGUOUS_TOKEN,且该类不产生 CSS;分支不会合并。
- 请用不同键,或 (font-size:var(--font-size-brand)) 这类显式原生声明。
静态参数
函数工具类与混入接受位置参数:无类型、<integer>、<number>、<string> 或 <custom-ident>。静态默认值用冒号指定,例如 --cols <integer>: 2。数字必须是数值字面量;网格数量与跨度必须为正整数。字符串参数必须加引号。
@utility pair(--size) { width: var(--size); height: var(--size);}使用 pair(2rem)。常规函数参数必须能在静态阶段确定。若函数或混入恰有一个无类型、无默认值的参数,且仅有一条完整值恰为 var(--parameter) 的原生声明,也接受符号式 var() 表达式。调用方引用原样保留,交由浏览器求值。其他函数拒绝外部 var()、attr() 及依赖浏览器的参数。已知的外层参数可通过 var(--parameter) 转发。
A parameter utility
@utility pair(--size) { width: var(--size); height: var(--size); } @safelist 'pair(2rem)';生成的 CSS
@layer utilities { .pair\(2rem\) { width: 2rem; height: 2rem }}静态配方参数不同于实时 CSS 值
图中的 pair 工具类有两条声明。另一项单参数、单声明的符号式引用例外不适用于此。
文字说明
- @utility pair(--size) { width: var(--size); height: var(--size); } 接受 pair(2rem) 的已知参数,并绑定到两条声明。
- 此配方拒绝 pair(var(--size)),因为参数依赖浏览器。需要保持实时变化的值,请用显式原生声明类。
- (width:var(--size)) 为浏览器保留变量引用,仅改变宽度。若也需要高度,请另加高度声明。
@mixin 与 @apply
Master 编译实验性 CSS Mixins 规范的静态子集。定义采用双连字符名称,且必须是不带条件的样式表级规则。混入提供 CSS 复用,不注册 Master 类。
@mixin --caption { font-size: var(--font-size-sm); line-height: 1.5;}.caption { color: currentColor; @apply --caption; font-weight: 600;}@utility caption { @apply --caption;}@apply 在原生规则、工具类或另一个混入内接受一个混入调用,不接受工具类名称或类列表。展开位于原有声明位置,并保留重复声明、重要性、选择器、条件与 URL 所有权。
参数可用于应用元素上,包括 &:hover 与条件包装。跨元素使用参数、重新赋值、选择器或条件插值、递归定义、重载、@private 及不支持的类型均报告编译错误。该静态子集未实现依赖浏览器的参数求值、私有属性或通用函数。
混入在调用位置展开
插入位置前后的相同行保持对齐。选择器、声明顺序和外层的层叠层仍由调用方拥有。
文字说明
- --caption 混入提供 font-size: 14px 和 line-height: 1.5。
- 在 .caption 内,@apply --caption 展开于 color: currentColor 与 font-weight: 600 之间。
- 展开不会注册类,也不会将原生规则移至生成层。重复声明和编写顺序均保留。
内容与类包装
使用 @contents 标记调用方的声明或嵌套规则插入可复用包装的位置。
@mixin --card-wide() { @container card (width >= 40rem) { @contents { display: grid; } }}.card { @apply --card-wide { gap: 1rem; }}@contents; 插入提供的内容。@contents { … } 仅在调用省略块时提供回退内容。显式空 @apply --card-wide {} 会抑制回退。每个 contents 位置插入一次块,保留声明、重复值与嵌套规则。没有 @contents 的混入忽略提供的块。
省略 contents 块与空块不同
混入包含 @contents { display: grid; }。调用处的花括号区分刻意留空与省略块。
文字说明
- @apply --panel; 省略 contents 块,使用 display: grid 回退内容。
- @apply --panel {} 提供空块,抑制回退,因此本例不添加声明。
- @apply --panel { display: flex; } 提供自身内容替换回退内容,两条 display 声明不会合并。
提供的内容保留调用方参数绑定,即使经嵌套应用转发也一样。回退内容使用定义混入的绑定。常规自定义属性保留原生 CSS 层叠行为。允许有限的嵌套调用;递归定义及超过展开深度或节点上限均为错误。
@mixin --hocus { &:is(:hover, :focus-visible) { @contents; }}@utility emphasis { color: red; display: block;}<button class="(color:red)@apply(--hocus)">Save</button><div class="grid-cols(3)@apply(--card-wide)"></div><div class="emphasis@apply(--hocus)!"></div>@apply(--name(...)) 接受静态参数。多个 @ 包装从左到右嵌套:(color:red)@apply(--a)@apply(--b) 将 --a 放在 --b 外层。工具类将所有声明作为一个块提供,因此包装自身的声明每个类仅输出一次。选择器后缀保留原有位置;末尾 ! 将每条展开声明标为重要。类头部与除 @apply 外的条件后缀决定类排序:每个外层条件分支都是独立排序的一条规则;混入内部选择器和条件留在输出文本中,不会让类移到较后排序级别,展开也保留原始顺序。若展开未添加声明、选择器或条件,就与单声明工具类一起排序;若头部为 (property:value),则与原生声明一起排序。其他展开按配方排序。检查与冲突分析使用展开后的规则。
未使用定义、丢弃的 contents 和未使用回退块不会保留令牌或关键帧。已交付原生 @apply 仍通过 emitted-globals 契约作为资源根节点。声明位置与相对 URL 保留其定义或调用文件。
包装决定调用方声明的位置
高亮插槽与插入声明位于选择器边界内的同一位置。包装控制声明的应用位置。
文字说明
- @mixin --hocus { &:is(:hover, :focus-visible) { @contents; } } 定义包含显式 contents 插槽的选择器包装。
- underline@apply(--hocus) 将 text-decoration-line: underline 提供给插槽。输出规则在任一状态下均可匹配类所属元素。
- 图示结果以 & 简写转义后的类所属元素,使位置易于阅读;生成 CSS 仍保留完整所属元素。
完整定义替换
较后的定义替换同一注册的完整主体,不合并声明。同名静态工具类与函数工具类属于独立注册。令牌模式仅替换解码后前缀与命名空间均相同的分支。
@utility badge { color: red; padding: 1rem;}@utility badge { color: blue;}badge 现在仅输出 color: blue。之前的 padding 及其依赖已移除。
较后定义完整替换注册
两个定义注册相同的静态工具类。第二个完整替换第一个,原有的 padding 也不再保留。这是生成前的定义替换,并非两条 CSS 规则在层叠中竞争。
文字说明
- 第一个静态 badge 定义包含 color: red 和 padding: 1rem。
- 较后的静态 badge 定义仅含 color: blue,并完整替换第一个定义。
- 使用 badge 生成一条包含 color: blue 的规则。之前的 padding 及其依赖不会保留。
- 静态与函数注册仍相互独立。令牌模式仅替换前缀与命名空间相同的分支;混入则替换完整命名定义。
混入名称仅有一个最终定义,包括参数列表、主体与依赖。空定义仍保持注册。前向嵌套调用依据最终注册表解析;不提供参数重载。
静态名称与函数独立注册
路径表示注册身份。名称相同不会使两个定义成为重载或合并主体。
文字说明
- @utility badge { display: inline-block; } 注册静态 badge 类。@utility badge(--inset) { padding: var(--inset); } 注册独立函数。
- 将静态定义改为 display: block 会改变 badge,但 badge(8px) 仍写入 padding: 8px。
- 替换影响的是同形式、同名称的完整主体。函数不是静态类的回退。
定义作用域与导入
@theme、@utility、@mixin、@custom-media 和 @custom-container 是顶层定义,在层或条件包装中注册会产生错误。混入主体可包含声明、嵌套选择器、支持的原生条件、嵌套 @apply 与 @contents。层位置由调用方决定。
源扫描、安全列表、引擎 API 和运行时 DOM 变更中的类均为使用根节点。已交付原生 CSS 中的 @apply 也是根节点;未使用工具类或混入内、或未交付 @reference 样式表内的则不是。依赖收集在参数绑定与 ident() 折叠后进行。已使用令牌保留有序声明和传递依赖。静态令牌即使没有引用方也保持根节点。移除最后一个根节点会释放资源;原生 CSS 资源则通过 emittedGlobals 保持固定。
运行时 manifest 保留未使用定义,供未来 DOM 类使用。按需生成针对 CSS 与资源输出。原生 CSS 裁剪仍须显式启用;关键帧与其声明文件共用原生保留和裁剪策略。带限定的导入只能包含原生 CSS。定义请通过不带限定的导入或引用加载。
原生属性优先顺序
原生 (property:value) 类的 CSS 属性含义独立于工具类注册。在相同条件下,单声明工具类与原生声明类可以覆盖配方的一部分。完整排序和覆盖规则见声明与值。
原生默认样式
将原生默认样式写在 @layer defaults 中。
原生组件
将原生组件选择器写在 @layer components 中。
@layer components { .button { display: inline-flex; padding: var(--spacing-md); &:focus-visible { outline: 2px solid currentColor; } }}原生规则按样式表导入图交付。工具类定义注册类名;混入定义通过 @apply 提供 CSS 复用。两者均在编译期间使用,仅被使用时才输出 CSS。
Sass 互操作
使用 Sass 时,请将 CSS 混入定义放在 .css 文件中。当前 Dart Sass 为未来 CSS 支持保留 @mixin --name,并拒绝将其视为 Sass 混入;请见 Sass 兼容性公告。SCSS 文件可在 Master CSS 编译前,通过插值输出原生 at-rule:
@#{'mixin'} --card { padding: 1rem;}.card { @apply --card; }这是 Sass 插值,并非额外的 Master CSS 语法。Sass @include 与 CSS @apply 仍是独立结构。
主题选择器包装
原生选择器和查询激活主题覆盖。混入可以提供对应的类条件:
@mixin --ocean { &:where([data-theme="ocean"], [data-theme="ocean"] *) { @contents; }}使用 (color:white)@apply(--ocean)。指向 shadow host 时,请显式添加 :host(...) 选择器。













