前端圈最近又整出新活儿了,CSS容器样式查询(Container Style Queries)这玩意儿还在超级早期的阶段,但已经能尝鲜了。Chromium早就支持,Safari从16版本也开始跟进,Firefox估计也快了。说白了,以前搞响应式只能盯着浏览器窗口宽度(视口)做文章,现在能直接看某个容器自身的样式属性来改变内部元素的长相,这波操作杠杠的。
概念整明白
容器样式查询,就是让一个容器把自己的样式值(比如背景色、字体风格)当成“检测开关”。当这个容器的某个CSS属性匹配上特定数值时,里头的子元素就自动换一套样式。打个比方:好比一个盒子穿上了橙色外套,盒子里的文字立马自动变成白色,不用手动加类名,也不用JS监听。这跟传统媒体查询不一样,媒体查询是看整个屏幕宽度,而样式查询是看身边那个老爹容器的样式。
实操走一波
想玩转这玩意儿,得先搭个测试环境。目前最稳当的是用Chrome Canary或者Safari Technology Preview,把“Experimental Web Platform Features”开关打开。下面一步步搞个能跑的例子。
第一步:定义一个容器
给外层元素起个名字,顺便声明它的查询类型。注意,按照最新的规范草案,样式查询其实不用特意写container-type: style,因为所有容器查询默认就支持样式查询。但为了代码清晰,可以写上。
/* 定义一个叫“card-box”的容器 */
.card-container {
container-name: card-box;
/* 下面这行可写可不写,写了更明白 */
container-type: style;
}第二步:容器本身带上某个样式
比如给这个容器来个橙色背景。这时候容器身上的background-color就成了一个“检测点”。
.card-container {
background-color: #f8a100;
}第三步:写样式查询规则
用@container后面跟上容器名字和要查询的样式条件。当card-box这个容器的背景色正好是#f8a100时,里面的.card文字颜色变成白色。
@container card-box (background-color: #f8a100) {
.card {
color: #fff;
}
}完整代码放一块儿:
<div class="card-container">
<div class="card">
这里是一段文字,当外层容器背景变橙色时,文字自动白起来。
</div>
</div>.card-container {
container-name: card-box;
background-color: #f8a100;
padding: 20px;
}
@container card-box (background-color: #f8a100) {
.card {
color: #fff;
font-weight: bold;
}
}运行一下,文字会变成白色。如果手动把.card-container的背景色改成别的颜色,比如#333,那个查询条件不满足,白色样式就失效了。这个过程完全自动,不用写一行JS。
写代码时有个小坑:样式查询里的属性值必须和容器上计算后的实际值完全匹配。比如background-color: #f8a100写成background-color: orange,浏览器可能不认,因为计算后的值往往是rgb格式。稳妥的做法是查一下开发者工具里Computed那一栏的精确值。
方案举个栗子
样式查询不止能玩背景色,还能拿自定义属性(CSS变量)当状态机,或者解决嵌套斜体的尴尬场面。下面整两个实际能用的方案。
方案A:自定义属性驱动卡片模式
有时候想根据一个“模式开关”来改变卡片内部的布局。不用加额外类名,改个变量值就行。
/* 定义容器,并给一个默认变量值 */
.dashboard {
container-name: dash;
--theme: light;
background: #fff;
}
/* 当变量值变成dark,内部文字和背景跟着翻 */
@container dash (--theme: dark) {
.card {
background: #222;
color: #eee;
}
.card-title {
border-bottom-color: #555;
}
}在JS里只需要改.dashboard的style.setProperty('--theme', 'dark'),所有卡片样式自动切换。相比传统方法挨个加类名,这玩意儿省心多了。
实际操作时注意:自定义属性作为查询条件,不能写var(--theme),直接写(--theme: dark)就行。而且目前浏览器支持还不太统一,建议搭配@supports做降级。
@supports (container-type: style) {
/* 支持样式查询的浏览器走新路子 */
@container dash (--theme: dark) {
.card { background: #222; }
}
}
@supports not (container-type: style) {
/* 不支持的浏览器用老办法 */
.dashboard.dark .card { background: #222; }
}方案B:干掉嵌套斜体的尴尬
写文章时经常碰到这种情况:一个blockquote里面已经用了斜体,结果引文里又来个em或i标签,斜体叠斜体,看着贼难受。样式查询能根据外层容器的font-style自动把内层斜体掰正。
blockquote {
container-name: quote;
font-style: italic;
}
/* 如果blockquote本身已经是斜体,里面的斜体标签就强制变正常 */
@container quote (font-style: italic) {
em, i, q, address {
font-style: normal;
}
}这么一搞,不管blockquote从哪儿继承来的斜体,只要它算出来是斜的,里头的em就自动站直了。不用操心类名,不用写一堆嵌套选择器。
部署这套方案时,记得给blockquote加上container-name,不然查询找不到目标。另外font-style的继承性可能导致预料之外的结果,比如外层父级是斜体,但blockquote自己没设font-style,计算值也是斜体,照样触发查询。这反而是个优点,因为查询的就是计算后的真实值。
| 方案名称 | 核心思路 | 适用场景 |
|---|---|---|
| 自定义属性驱动 | 改CSS变量值触发内部样式 | 主题切换、状态面板 |
| 嵌套斜体修正 | 检测父级斜体状态重置子元素 | 富文本排版、引文区 |
最后提醒一嘴,目前样式查询在规范里还属于“毛坯房”阶段,语法可能微调。但基本原理已经定下来了:容器有啥样式,里面的孩子就跟着变。这货未来绝对是CSS界的王炸,现在提前上车,等浏览器全量支持时直接起飞。
