容器查询启用基于可用空间的元素样式。它们使我们能够构建可适应无限、未知布局安排的弹性组件。这与视口媒体查询形成对比,视口媒体查询需要在页面级别协调样式更改。
容器查询与视口媒体查询
我们很可能熟悉响应视口的响应式设计和布局,如下图所示。
在视口响应式设计中,将布局网格耦合到断点很流行。这些断点通常与简化的设备尺寸有关,如上图所示,例如手机、平板电脑和台式机。
重要的是,这些断点不一定考虑屏幕上的单个元素和组件,更侧重于组件如何流入预定义的网格。有时,较大的组件(如导航)会与网格分开变形,但通常它们会使用全局断点。
让我们将视口响应式设计与容器响应式设计进行对比。
下图是卡片组件的变体。这三种变体是使用完全独立于视口的容器查询呈现的。卡片样式根据可用空间进行调整。
注意:自 Firefox 110 发布以来,所有常青浏览器都支持容器查询。为了扩展对旧浏览器的支持,可以使用 polyfill。
首先,让我们学习创建容器查询的语法。
定义容器查询
第一步是使用属性指定元素是容器container-type
。最基本且目前支持最好的值是inline-size
,在水平书写模式下它等于元素的宽度。所以这个定义意味着我们打算支持基于.container
元素的行内大小的查询:
.container { container-type: inline-size; }
向元素添加 acontainer-type
正式将其指定为容器。
接下来,我们将使用容器 at 规则创建实际的容器查询,如果我们曾经分配过媒体查询,它会接受一个看起来很熟悉的参数。
下面的@container
规则说,当 an<h2>
在一个40ch
宽或更大的容器内时,它的颜色应该是蓝色:
@container (min-width: 40ch) { h2 { color: blue; } }
注意:我们放置在容器查询中的规则不会影响容器本身的样式,只会影响其子项。这意味着我们无法从容器自身的查询中设置容器的样式。但是,如果容器的祖先也被定义为容器,我们可以使用容器查询来设置容器的样式。
为了适应不仅仅是水平书写模式,我们可以更新我们的查询以使用 的逻辑语法inline-size
,而不是严格基于容器的“宽度”查询:
@container (inline-size > 40ch) { h2 { color: blue; } }
还有更多选项inline-size
,包括block-size
和aspect-ratio
。要了解有关可用大小容器查询以及如何使用它们的更多信息,请查看官方规范。
升级卡片组件
如果我们想构建一个没有容器查询的卡片组件,我们可以通过修饰类创建变体。对于卡片大小的变化,这些修饰符可以与断点相关联。这意味着,如果卡片有修饰符,则当视口宽度落在该断点内时,它会被允许更改。
下图显示了三种卡片大小变化及其各自的修改器类别,其中顶部.card
将被视为“默认”。
现在让我们换个角度思考如何使用容器查询来处理这些卡片变体。
我们仍会将顶部卡片设为默认卡片,这实际上意味着它将应用于最窄的宽度。这也将是不支持容器查询的回退版本——在容器查询达到支持成熟度之前需要考虑的一个重要场景。
我们将为中型卡片(水平方向)设置布局,以便在容器宽度为350px
或更大时激活。
最后,当容器的宽度为600px
或更大时,我们将卡片布局设置为使用其图像作为背景。
这将创建一个可根据卡片容器的大小进行调整的卡片元素。试玩以下CodePen 演示以了解实际效果。(请注意右下角的“调整我的大小!”手柄。)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .card { --img-ratio: 2/1; display: grid; gap: 1rem; padding: 1rem; box-shadow: 0 0 0.5rem rgba(0, 0, 0, 0.35); border-radius: 0.5rem; } .card > img { height: max(18vh, 12rem); object-fit: cover; width: 100%; } @supports (aspect-ratio: 1) { .card > img { aspect-ratio: var(--img-ratio); height: auto; } } .card__content > :not(h2, h3, h4) { font-size: 0.9rem; } .card__content { display: grid; gap: 0.5rem; gap: 1cqb; } .card-list { align-items: start; } .card-list li { container-type: inline-size; } @container (min-width: 350px) { .card { --img-ratio: 1; grid-auto-flow: column; align-items: center; } } @container (min-width: 600px) { .card { --img-ratio: 2/1; grid-template-areas: "card"; place-items: center; padding: 0; overflow: hidden; } .card > * { grid-area: card; } .card__content { text-align: center; color: #fff; padding: 1rem; } .card__content { font-size: 2rem; } } </style> </head> <body> <aside role="note"> <p>Your browser doesn't natively support container queries, but the demo works thanks to the polyfill! Refer to the JS tab for how to include it.</p> </aside> <ul role="list" class="flexbox-grid card-list container resize"> <li> <div class="card"> <img src="https://assets.codepen.io/1101822/jellyfish.jpg" alt="Pink and purple small flourescent jellyfish with white spotted caps float in inky darkness." width="400" height="300"> <div class="card__content"> <h3>Dolor sit amet</h3> <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit.</p> </div> </div> </li> <li> <div class="card"> <img src="https://assets.codepen.io/1101822/jellyfish.jpg" alt="Pink and purple small flourescent jellyfish with white spotted caps float in inky darkness." width="400" height="300"> <div class="card__content"> <h3>Dolor sit amet</h3> <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit.</p> </div> </div> </li> <li> <div class="card"> <img src="https://assets.codepen.io/1101822/jellyfish.jpg" alt="Pink and purple small flourescent jellyfish with white spotted caps float in inky darkness." width="400" height="300"> <div class="card__content"> <h3>Dolor sit amet</h3> <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit.</p> </div> </div> </li> </ul> <script> // Support Test const supportsContainerQueries = "container" in document.documentElement.style; // Conditional Import if (!supportsContainerQueries) { import("https://cdn.skypack.dev/container-query-polyfill"); } </script> </body> </html>
网友评论文明上网理性发言 已有0人参与
发表评论: