使用样式查询 (@container style()) 触发上下文变体,而无需对产生或响应每个上下文的内容进行硬编码。这可以减少设计体系耦合,并提高可扩展性和组件封装性。
例如,section.featured { --surface: featured } 规则可以标记上下文,着陆页也可能通过 main { --surface: featured } 默认使用该上下文。然后,组件会选择启用对 --surface: featured 的响应:卡片会显示促销徽章,按钮会默认显示其填充变体,等等。
样式查询可让双方保持解耦:精选界面绝不会命名适应它们的元素,组件也绝不会检查产生上下文的内容。任何一端都可以独立扩展(新组件、新功能界面),而不会影响另一端。后代选择器(例如 .featured .button)则恰恰相反:选择器必须对关系的两端进行编码,并且只要其中一端发生变化,选择器就必须随之更改。
何时使用本指南
本指南涵盖行为变化:组件根据其上下文决定要呈现的内容、如何排列自身或呈现哪个变体,例如隐藏或显示标记、切换布局方向或交换按钮变体。
如果您需要进行令牌级更改(例如密度模式、主题或其他高阶令牌,这些令牌会在多个组件中统一更改内边距和颜色等值),请参阅设计令牌响应性。
选择合适的工具
当上下文关系的两端可能独立变化时,请使用样式查询。例如,新元素可能开始产生上下文,或者新组件可能开始对上下文做出反应。这种间接方式在可扩展性和封装性方面物有所值,并且样式查询可以跨越后代选择器无法跨越的 shadow DOM 边界。如果不需要这种灵活性,请首选更简单的工具:
- 后代选择器 (
.toolbar .button):一种固定的、一次性的关系,不可重复使用或扩展。遵循 YAGNI 原则:不要添加不会使用的间接层。 - 尺寸查询 (
@container (min-width: …)):由可用空间(而非语义状态)驱动的布局和密度变化。 - 样式查询 (
@container style(…)):语义状态,即组件在给定上下文中应呈现、排列或展示的内容。
实现指令
- 使用容器上的 CSS 自定义属性定义语义上下文标志。
- 请勿为样式查询设置
container-type;样式查询会查询最近祖先元素上继承的自定义属性,不需要显式包含上下文。 - 强制性:使用
@container style(--property: value)将条件样式应用于后代元素。样式查询无法匹配设置了属性的元素,只能匹配其后代。 - 如果关系必须保持可扩展性或跨组件/影子 DOM 边界,请优先使用样式查询,而不是后代选择器(请参阅上文的选择合适的工具),但对于固定的一次性关系,请保留后代选择器,因为间接性不会带来任何好处。
实现示例
/* 1. Set the context on a layout container */
.featured {
--surface: featured; /* Semantic context flag for children */
}
/* 2. Component reacts to inherited flag */
.button {
/* Default: Outlined informational style */
background: transparent;
border: 1px solid currentColor;
}
.badge {
/* Default: Hidden — only revealed in featured surfaces */
display: none;
}
@container style(--surface: featured) {
.button {
/* Automatic switch to Filled promotional style */
background: var(--brand-accent);
color: white;
border: none;
}
.badge {
/* Reveal decorative elements only in featured context */
display: block;
}
}
后备策略
在容器样式查询广泛可用之前,请将其作为渐进增强功能进行分层:提供一个可在任何地方运行的基于选择器的默认样式,并在支持时让样式查询替换它。在上下文选择器上使用 :where(),以便样式查询(特异性相同,在源代码顺序中靠后)自动胜出。
/* Default styles — work everywhere */
.button {
background: transparent;
border: 1px solid currentColor;
}
.badge {
display: none;
}
/* Selector-based contextual styles — broad browser support */
:where(.featured) .button {
background: var(--brand-accent);
color: white;
border: none;
}
:where(.featured) .badge {
display: block;
}
/* Progressive enhancement: style queries override when supported */
@container style(--surface: featured) {
.button {
background: var(--brand-accent);
color: white;
border: none;
}
.badge {
display: block;
}
}
选择器后备会将情境样式与类名相关联,从而将组件与其 DOM 放置位置相关联。样式查询得到广泛支持后,即可移除 :where() 规则。