你以为组件状态只能靠 JS 写一堆 class?今天 CSS 把这件事彻底原生化了
做过中后台系统的工程师大概都踩过这个坑——一个卡片组件有 default/primary/danger 三种状态,传统的做法是在 JS 里写 el.classList.toggle("card--" + variant),然后在 CSS 里写三段 .card--primary { ... } .card--danger { ... } 规则。每加一个状态,JS 要改、CSS 要改,两边的 class 名还要对得上。
CSS Style Queries 把这件事彻底变了——父容器上写一行 --variant: primary,子元素自己知道该用什么样式,JS 不用动一行。
原理
Style Queries 是 CSS Container Queries 的一部分,用 @container style() 查询祖先容器上的自定义属性值:
/* 1. 父容器声明自己是查询容器 */
.card-wrap {
container-name: card;
container-type: inline-size;
}
/* 2. 用 @property 注册自定义属性(建议加类型注册) */
@property --variant {
syntax: "<ident>";
initial-value: default;
inherits: true;
}
/* 3. 在父容器上写状态值 */
.card-wrap {
--variant: primary;
}
/* 4. 子元素根据父容器属性自动响应 */
@container card style(--variant: primary) {
.card {
background: oklch(0.55 0.2 260);
color: #fff;
}
}
@container card style(--variant: danger) {
.card {
background: oklch(0.55 0.2 30);
color: #fff;
}
}
对比传统方案:
// 传统 JS 方案:每改一次状态要改两处
el.classList.remove("card--default", "card--primary", "card--danger");
el.classList.add("card--" + variant);
Style Queries 的本质是:把状态写在父容器上,样式向下级联自动响应。JS 只需要改父容器的一个属性值,不需要在每个子元素上做 class 操作。
三个常见坑
坑一:查询的目标不是自己
Style Query 查的是祖先容器,不是元素自己。在 .card-wrap 上查 --variant 会匹配 .card-wrap 上的值;但如果把 @container style() 写在 .card-wrap 自己身上,是不会生效的。规则只能查祖先,不能查自己。
坑二:@property 注册类型让查询更可靠
如果不注册 --variant 的类型,浏览器会把它当作无类型字符串。注册之后,Safari 和 Firefox 的行为会更一致:
@property --variant {
syntax: "<ident>";
initial-value: default;
inherits: true;
}
没注册也能用,但注册之后 initial-value: default 确保未设置该属性的父容器也能匹配 style(--variant: default) 的兜底规则。
坑三:只能查自定义属性,不能查普通 CSS 属性
这是目前最大的限制——@container style(color: red) 在任何浏览器里都不生效,只能查 --custom-property: value。所以这套方案依赖组件提前把状态变量化,变成 --status --density --size 这类自定义属性。
Style Queries 完整三件套
Container Queries 其实有三类,Style Queries 是其中之一:
- 尺寸查询
@container card (min-width: 400px)—— 查容器宽度,Baseline 2023 - 样式查询
@container card style(--variant: primary)—— 查容器属性,Baseline 2026(新增) - 滚动状态查询
@container scroll-state(scrolled-y)—— 查滚动方向,Chrome 133+
三者可以叠加:@container card style(--variant: danger) and (min-width: 400px) 表示在 danger 状态且宽度大于 400px 时生效。
浏览器支持
Style Queries(仅自定义属性查询):Chrome 111+/Safari 18+/Firefox 151+。2026 年 5 月 Firefox 151 发布后,四大主流浏览器全部支持,Baseline 2026(新增可用),91.7% 全球覆盖率,已可投入生产。
滚动状态查询 @container scroll-state() 目前仅 Chrome 133+ 支持,需要渐进增强。
三步下一步
- 列清单:把组件里 JS 正在管理的
data-*属性/状态变量列出来,把data-variant→--variant、data-status→--status映射好 - 注册类型:用
@property注册这些状态属性,设定initial-value为默认值,inherits: true确保嵌套组件也能读到 - 写查询规则:把原来
.btn--primary里的样式迁移到@container style(--variant: primary)里,删掉 JS 里的 classList 操作
想消除 JS class 切换的工程团队,现在可以动手了。Style Queries 已在四大浏览器稳定支持,91.7% 全球覆盖,CSS 逻辑层正在把「状态」这件事从 JS 手里接过来。
评论区
登录后可评论。