一、浏览器正式支持了
Chrome105和Safari16已经正式支持@container规则了,见下图。
Chrome105我是前几周升级的(上个月发布),Safari16是上周升级的(两周前发布),时间很接近。
现在体验@container规则已经无需开启"支持实验性质CSS"选项,此时写文章,读者体验demo的时候可以直观地看到效果,介绍@container规则正是时候。
//zxx: 如果你看到这段文字,说明你现在访问是不是原文站点,更好的阅读体验在这里:https://www.zhangxinxu.com/wordpress/?p=10554(作者张鑫旭)
二、@container规则干嘛用的
@container规则,也称@container查询,可以实时匹配指定为容器元素的尺寸,开发者可以基于不同的尺寸范围,对内部的元素进行特定的样式设置与布局实现。
大家应该都知道@media媒体查询中有个尺寸匹配,例如:
@media (max-width:1024px) {}
然后该规则中的CSS声明会在屏幕宽度小于1024px的时候执行。
而@container规则有些与之类似,只是匹配的尺寸对象不同。
@media匹配的是浏览器窗体,而@container匹配的是某个元素。
所以,业界就有这样的说法,@media查询适用于宏观布局,@container查询适用于微观布局。
演示实例
需要知道支持,然后改变布局和版式的例子非常多,我想想,找个合适的,最近遇到个按钮组换行的例子,可以使用@container规则解决,不过这个案例不具有典型性,比较小。
嗯......啊,刷了会儿钓鱼视频,我突然想到了一个困扰已久的技术难题,就是一个div元素内的文字的font-size字号随着宽度减小而减小。
赶快做个demo,然而......
......人算不如天算......
我发现,这个需求不需要使用@container
规则,直接使用容器查询单位就可以实现了......
三、cqw等容器尺寸单位与动态字号大小
随着CSS容器查询一起出现的还有CSS容器查询单位,包括:cqw
, cqh
, cqi
, cqb
, cqmin
和 cqmax
。
其中:
| 单位名称 | 释义 | |-------|-----------------------------------------------------------------------------------------------------| | cqw | 表示容器查询宽度(Container Query Width)占比。1cqw等于容器宽度的1%。假设容器宽度是1000px,则此时1cqw对应的计算值就是10px。 | | cqh | 表示容器查询高度(Container Query Height)占比。1cqh等于容器高度的1%。 | | cqi | 表示容器查询内联方向尺寸(Container Query Inline-Size)占比。默认情况下,Inline-Size指的就是水平方向,对应的是宽度,因此,1cqi通常可以看成是容器宽度的1%。 | | cqb | 表示容器查询块级方向尺寸(Container Query Block-Size)占比。默认情况下,Block-Size指的就是垂直方向,对应的是高度,因此,1cqb通常可以看成是容器高度的1%。 | | cqmin | 表示容器查询较小尺寸的(Container Query Min)占比,例如容器尺寸是300px*400px,则100cqmin对应的是尺寸较小的宽度300px,而非高度。 | | cqmax | 表示容器查询较大尺寸的(Container Query Min)占比。 |
从某种程度上讲,cqw
, cqh
、cqmin
、cqmax
单位和vw
, vh
、vmin
、vmax
单位语法和含义是一致的,只是一个是相对于容器尺寸,另外一个是相对于视区(ViewPort)尺寸。
真·演示实例
回到上面的demo需求,实现基于浏览器宽度而字号变化的需求,其实很简单,两行 CSS 代码就可以了,假设 HTML 如下所示:
<div class="container">
<p>群众的眼睛是雪亮了,《CSS新世界》上架快一年了依然排在京东Web开发书籍前几。</p>
</div>
CSS 这样就实现了:
.container {
container-type: inline-size;
}
.container p {
font-size: clamp(.75rem, calc(100cqw / 40), 2rem);
}
表示文字字号在0.75rem-2rem之间变化,字号是2.5%容器宽度,算算,一行可以放40个汉字。
实现的效果如下GIF所示:
眼见为实,您可以狠狠地点击这里:CSS @container查询让字号随宽度变化demo
OK,在本例中,出现了 container-type
这个CSS属性,想必很多人都没见过。
这个CSS属性可以让普通的元素变成容器元素(控制台元素面板中可以看到对应的标识):
此时 cqw 单位就相对于这个元素计算,以及 @container 规则也有了匹配对象。
三、终于轮到@container规则了
如果希望元素在某个尺寸范围内出现较为明显的布局或样式变化,那么就需要用到@container规则。
举个例子,还是上面那个字号变化的例子,如果希望容器宽度小于480px的时候左对齐,同时文字加粗,则可以使用如下所示的CSS实现:
.container {
container-type: inline-size;
}
.container p {
font-size: clamp(.75rem, calc(100cqw / 40), 2rem);
text-align: center;
}
@container (max-width: 480px) {
.container p {
text-align: left;
font-weight: bold;
}
}
此时,当容器宽度小到一定程度的时候,就会文字加粗,如下GIF所示:
眼见为实,您可以狠狠地点击这里:CSS @container查询让文字样式变化demo
作用原理
凡是写在@container规则中的CSS语句,都会寻找最近的容器元素,并进行匹配。
例如,上面的例子中,.container p
匹配的元素最近的容器元素就是.container
元素,因此,会在.container
元素尺寸小于480px的时候,渲染@container规则中的CSS语句。
如果页面中没有任何元素是容器元素(也就是没有元素设置container
属性),则@container是不会执行的,同时cqw单位会按照浏览器窗体尺寸就像计算(等同于vw)。
所以@container规则生效的前提就是需要先声明容器元素,使用的是CSS container
属性。
四、说说container属性
container
属性是container-type
和container-name
这两个属性的缩写。
container-type
上面已经演示过了,表示指向容器的类型,是水平方向的(对应宽度),还是包括垂直方向的(对应宽度和高度)。
语法如下:
container-type: normal;
container-type: size;
container-type: inline-size;
其中normal
是默认值,表示不建立容器元素,size
表示水平和垂直方向都建立,inline-size
是只在水平方向建立,会给元素同时应用layout、style和inline-size容器状态(关于这个,可以详见《CSS新世界》中关于contain属性的介绍,在P535)。
container-name的作用
container-name
的作用是给容器元素命名,这个属性在页面中存在多个容器元素的时候很有用。
假设如下CSS代码:
@container (max-width: 480px) {
p {
font-weight: bold;
}
}
如果页面中存在多个容器元素,则这些元素中的 <p>
元素都会应用 font-weight:bold
,但我们的初衷可能就只有某一个容器元素才应用相关样式,此时container-name
就很有作用了。
例如:
.container-a {
container: aside / inline-size;
}
.container-b {
container: banner / inline-size;
}
@container banner (max-width: 480px) {
p {
font-weight: bold;
}
}
此时,只有banner
这容器元素内的 <p>
元素才会文字加粗。
补充一些实际使用经验于2023-03-08
-
container属性合写(就是container-name和container-type缩写)是无效的,需要分开书写,不知道是不是自己使用问题(经评论提醒,是使用斜杠分隔,非空格),还是浏览器并未支持,前者概率高一点。
-
@container规则作用在纯内联元素上是无效的,如果是内联块级元素,或内联弹性元素、内联网格元素,则尺寸会表现为0。
随后我进一步深入测试,发现,只要容器元素的尺寸表现为 fit-content,例如flex子项,绝对定位元素、float浮动元素,或者设置了 width: fit-content 的元素,其最终渲染宽度都会是0,以至于后面的内容会直接和元素重叠,Safari、Firefox或者Chrome均表现如此,这倒是挺有意思的。
其他更新于2023-03-08
- 现在现代浏览器媒体查询已经支持直接使用大于号小于号了,因此,不超过480宽度的判断语法也可以写作:
@container banner (width < 480px) {
p {
font-weight: bold;
}
}
- 容器查询还支持嵌套,例如(MDN文档):
@container summary (min-width: 400px) {
@container (min-width: 800px) {
/* 这里写样式... */
}
}
五、再说点其他的
世面上有不少介绍@contianer的文章(可能因为文章写得早,那时候浏览器还未正式支持)中容器元素的创建使用的是下面的 CSS 代码:
contain: layout inline-size;
虽然上述代码也能创建容器元素,但是根据我的测试,却无法响应@container
规则。
大家请使用全新的专门设计的contianer
属性进行定义。
以及cqw等容器查询单位一开始也不叫这个,而是叫"qw",没有前面的 "c",我用Chrome浏览器测试了下,是不支持所谓的 qw 单位的。
好,就说这些。
最后,再夸一句,容器尺寸查询很强,很多以前必须借助 JavaScript 才能实现的效果,现在纯 CSS 就能轻松驾驭。
以后等我实践一番,再补充几个经典案例。
感谢阅读,欢迎转发!
(本篇完)