当前位置: 首页 > article >正文

【CSS in Depth 2 精译_062】第 10 章 CSS 中的容器查询(@container)概述 + 10.1 容器查询的一个简单示例

当前内容所在位置(可进入专栏查看其他译好的章节内容)

  • 【第十章 CSS 容器查询】 ✔️
    • 10.1 容器查询的一个简单示例 ✔️
      • 10.1.1 容器尺寸查询的用法 ✔️
    • 10.2 深入理解容器
    • 10.3 与容器相关的单位
    • 10.4 容器样式查询的用法
    • 10.5 本章小结

文章目录

  • 第 10 章 容器查询
    • 10.1 容器查询的一个简单示例 A basic example of a container query
      • 10.1.1 容器尺寸查询的用法 Using container size queries

《CSS in Depth》新版封面

《CSS in Depth》新版封面

译者按
终于又来到了第2版的另一个全新章节——第十章的 CSS 容器查询。虽然各大主流浏览器对该语法支持已经有一年多了,启用该特性也无需依赖浏览器的实验环境,但系统介绍容器查询的高质量技术博文依然屈指可数。新特性的掌握主要分两步走:先不折不扣地学一遍,然后再想方设法投入实践。而前者的另一个窍门,则是结合具体的示例场景加深理解。精心挑选的示例在 CSS 新语法特性的学习过程中极为重要,但也是博文创作者经常忽视的一个环节,毕竟经典案例需要作者自己先吃透该知识点。让我们跟随作者的思路,一次性拿下这个业界期盼已久的容器查询功能!!!

第 10 章 容器查询

本章概要

  • 容器的定义与 @container 规则的用法
  • 根据容器大小实现模块的响应式
  • 容器相对单位的用法
  • 利用样式查询实现基于自定义属性值的样式变更

至此我们已经掌握了将 CSS 组织为方便重用的模块的具体方法。在大型项目团队构建大型网站或 Web 应用时,利用该方法可以得到效果完全一致的 CSS 样式。然而,要是遇到响应式设计的场景,要让设计出的模块在页面任意位置都能使用,难度就会直线攀升。可能经常会遇到要将某个模块放入像侧边栏这样的狭长的列内。虽然视口本身可能够宽了,但留给特定模块的可用空间就另说了。因此,普通的 @media 媒体查询在模块的响应式设计方面未必可行。

而 CSS 新推出的 容器查询(container query 功能则提供了更为灵活实用的解决方案。容器查询分为两大类:容器尺寸查询(container size queries)容器样式查询(container style queries)。前者可以根据容器元素的宽度调整页面元素的样式;而后者则可以根据容器的自定义属性实现样式修改。

容器的定义

在容器查询的语境下,容器(container 是指包含了相关元素的特定祖先元素。容器可以是父元素或者更高层级的 DOM 树节点。容器元素在容器尺寸查询和容器样式查询中有各自的确定方式,稍后会详述。

本章将对媒体查询的局限性作简要说明,并介绍容器查询在响应式设计中的具体用法。之后将结合几个实际案例进行深入探讨,助您彻底拿下这个前端期盼已久 CSS 特性。

10.1 容器查询的一个简单示例 A basic example of a container query

不妨再来仔细考察一下上一章介绍过的媒体模块(如图 10.1 所示)。先将该模块添加到一个简单的两栏布局中,并让页面符合响应式的设计要求,以便在视口尺寸较小时两个内容列可以呈上下分布。下面将演示在页面响应式特性的控制上,尤其是在涉及模块化 CSS 的相关场景时,媒体查询的表现未必会令人满意。

图 10.1 第 9 章中构建的媒体模块效果图

【图 10.1 第 9 章中构建的媒体模块效果图】

上述模块的 HTML 标记如以下代码清单 10.1 所示。媒体模块位于一个 <aside> 元素内,该元素在页面上渲染为一个狭长的侧边栏列。

代码清单 10.1 带媒体模块的简单两栏布局页 HTML 标记

<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport"
      content="width=device-width, initial-scale=1" /><!-- 视口的 meta 标签 -->
    <link href="style.css" rel="stylesheet" />
  </head>
  <body class="l-page">
    <main>
      <h1>Franklin Running Club</h1>
    </main>
    <aside>
      <h3>Running tips</h3>
      <div class="media"><!-- 媒体模块 -->
        <img class="media__image" src="runner.png" />
        <div class="media__body">
          <h4>Change it up</h4>
          <p>
            Don't run the same every time you
            hit the road. Vary your pace, and
            vary the distance of your runs.
          </p>
        </div>
      </div>
    </aside>
  </body>
</html>

此时,正文列 main 元素中并没有多少内容,本章稍后会进行扩充。这里先关注侧边栏中的媒体模块。

接着打开样式表,并根据代码清单 10.2 提供的样式进行更新。此时页面中的媒体模块效果和上一章相比,除了引入一些媒体查询来实现页面的响应式外,并没有什么不同之处。整体的页面布局也使用了一个媒体查询,以便在视口尺寸较小时,整个侧边栏可以叠放在 <main> 元素的下方。该写法本质上与第 7 章介绍过的响应式知识是一样的。

代码清单 10.2 两栏布局与媒体模块的样式代码

@layer reset, layout, modules;

@layer base {
  img {
    display: block;
    max-width: 100%;
  }
}

@layer layout {
  .l-page {
    margin-inline: 1rem;
  }

  @media (min-width: 800px) { /* 大尺寸视口下使用双栏布局 */
    .l-page {
      display: grid;
      gap: 1rem;
      grid-template-columns: 1fr 30%;
    }
  }
}

@layer modules {
  .media {
    padding: 1.5rem;
    background-color: #eee;
    border-radius: 5px;
  }

  .media__image {
    margin-inline: auto;
  }

  @media (min-width: 450px) { /* 对于 450px 以上的视口,将文本移至图片旁边 */
    .media {
      display: flex;
      gap: 1.5em;
    }

    .media__image {
      align-self: start;
      margin-inline: revert;
    }
  }
}

在浏览器中加载该页面,媒体模块会出现在较窄的右边栏;而当视口尺寸变得很小时,各列又会叠放在一起,同时媒体模块内部元素也会发生堆叠,最终令图片出现在文本上方,如下图 10.2 所示。由于在小尺寸断点的图片上设置了 margin-inline: auto,因此图片可以水平居中展示。

图 10.2 媒体模块在小尺寸视口的响应式页面中的叠放效果图

【图 10.2 媒体模块在小尺寸视口的响应式页面中的叠放效果图】

在本例中,页面所有内容在视口尺寸较大时显示正常,在视口较小时页面的响应式渲染也表现良好;然而,当视口尺寸处在二者之间时,情况就不太理想了。当视口宽度稍微迈过 800px 时,页面会按两栏布局渲染。此时右边栏的宽度无法按响应式设计很好地处理媒体模块的渲染,导致媒体模块中的文本内容被强行挤到一处非常狭窄的位置,如图 10.3 所示:

图 10.3 两栏布局中的侧边栏由于宽度不够,无法正确处理媒体模块的渲染

【图 10.3 两栏布局中的侧边栏由于宽度不够,无法正确处理媒体模块的渲染】

这里的媒体查询模块的问题在于,尽管视口本身的宽度已经够宽了,似乎可以按并排模式来渲染媒体模块了;但媒体模块却被放到了一个宽度严重不足的容器内。

这个问题理论上可以通过再加一个媒体查询来解决。这样一来,当视口宽度介于 800px 到大约 1100px 之间时,媒体模块将位于较窄的侧边栏内,并按照一个“动态的”(“mobile”)上下布局进行渲染。这无疑需要写更多样式代码,并且还得时刻关注页面其他位置是否也有类似的狭窄容器;更要命的是,这样的解决方案严重违背了模块化设计的一个核心原则:设计模块时不应该依赖可能会用到该模块的上下文。

一种更好地解决方案是完全放弃媒体查询,转而使用 容器查询。使用了容器查询的模块,视口大小与否都无关紧要;重要的是该模块所在的容器大小。

10.1.1 容器尺寸查询的用法 Using container size queries

启用容器尺寸查询只需两个步骤:先定义一个 容器(container,再用 @container 规则查询该容器。接下来将通过容器查询的一个简单示例来完善刚才的媒体模块,之后将带您深入考察定义容器时可用的其他配置项。

注意

容器查询功能虽然已于 2023 年初得到了当时所有主流浏览器最新版的支持,但在决定是否使用该功能时,也要考虑到用户可能推迟升级浏览器的情况。获取浏览器最新的版本支持情况,详见 https://caniuse.com/css-container-queries。

在 CSS 中,容器 这一术语长期以来一直用于指代某个祖先级元素,并通过指定尺寸大小或背景颜色来界定页面上的某个区域;而在容器查询的上下文中同样如此。但在容器尺寸查询中,必须通过设置 container-type 属性来显式定义容器。您也可以在同一元素上设置 container-name,例如:

container-name: layout;
container-type: inline-size;

这样就给容器指定了一个名称 layout,并且限定开发者只能根据其行内尺寸或宽度进行容器查询。稍后我们还将重点考察这些属性中的各种取值,但眼下这些配置已经足以构建出一个容器查询的基本示例了。

上述两个属性声明也可以通过 container 简写属性等效替换。这通常也是设置它们的最简单的方式:

container: layout / inline-size;

定义好了容器,就可以使用 @container 来查询宽度了,然后再对容器内的任意元素设置相应的样式。具体写法类似于媒体查询,例如 @container layout (min-width: 450px);或者使用带区间范围的写法 @container layout (width >= 450px)。这里的 layout 指代容器上定义的容器名称。当目标容器满足指定的尺寸大小时,该查询内的样式声明就会生效,在本例中即为:当容器的宽度大于或等于 450px 时生效对应的样式。

代码清单 10.3 给出了示例媒体模块的容器查询样式代码,请按照以下内容更新本地样式表。

代码清单 10.3 添加容器查询后的示例样式代码

@layer layout {
  .l-page {
    margin-inline: 1rem;
  }

  .l-page > * {
    container: layout / inline-size; /* 令每列均为一个容器 */
  }

  @media (min-width: 800px) {
    .l-page {
      display: grid;
      gap: 1rem;
      grid-template-columns: 1fr 30%;
    }
  }
}

@layer modules {
  .media {
    padding: 1.5rem;
    background-color: #eee;
    border-radius: 5px;
  }

  .media__image {
    margin-inline: auto;
  }

  @container layout (width >= 450px) { /* 查询 layout 容器的宽度 */
    .media {
      display: flex;
      gap: 1.5em;
    }

    .media__image {
      align-self: start;
      margin-inline: revert;
    }
  }
}

通过调整浏览器窗口大小来查看上述变更情况(或者利用浏览器的 DevTools 开发者工具启用响应式的设计模式)。此时,媒体模块相当于拥有了四个断点尺寸:在小尺寸视口中作上下布局排列;宽度介于 450px800px 时则恢复为水平布局;宽度介于 800px 到约 1530px 时(即侧边栏较窄时)再次作上下排列;最后当宽度大于该断点时,又恢复为水平布局排列。

更重要的是,侧边栏的代码和媒体模块的代码并没有纠缠到一起,可以放心修改二者中的任意一个。至于媒体模块在哪个上下文里响应哪种布局,则完全交由浏览器自行决定。

警告

鉴于容器的固有特性,需要严格遵守一项特殊规定:容器查询不能在容器本身指定样式。容器查询中的选择器只能选中容器内的 后代元素

与媒体查询一样,您也可以使用 not 关键字来对查询逻辑取反,令样式声明在查询条件为 false 时生效,例如 @container layout not (width >= 450px)



关于《CSS in Depth》(中译本书名《深入解析 CSS》)

第 1 版第 2 版
读者评分原版:4.7(亚马逊);中文版:9.3(豆瓣)原版:5.0(亚马逊);中文版:暂无,待出版
出版时间原版:2018 年 3 月;中文版:2020 年 4 月原版:2024 年 7 月;中文版:暂无,待出版
原价原版:$44.99;中文版:¥139.00原版:$59.99;中文版:暂无,待出版
现价原版:$36.49;中文版:¥52.54 起步原版:$52.09;中文版:暂无,待出版
原版国内预订起步价 ¥461.00起步价 ¥750.00

本专栏为该书第 2 版高分译文专栏,全网首发,精译精校,持续更新,计划今年内完成全书翻译,敬请期待!!!

目前已完结的章节(可进入本专栏查看详情,连载期间完全免费):

  • 第一章 层叠、优先级与继承(已完结)
    • 1.1 层叠
    • 1.2 继承
    • 1.3 特殊值
    • 1.4 简写属性
    • 1.5 CSS 渐进式增强技术
    • 1.6 本章小结
  • 第二章 相对单位(已完结)
    • 2.1 相对单位的威力
    • 2.2 em 与 rem
    • 2.3 告别像素思维
    • 2.4 视口的相对单位
    • 2.5 无单位的数值与行高
    • 2.6 自定义属性
    • 2.7 本章小结
  • 第三章 文档流与盒模型(已完结)
    • 3.1 常规文档流
    • 3.2 盒模型
    • 3.3 元素的高度
    • 3.4 负的外边距
    • 3.5 外边距折叠
    • 3.6 容器内的元素间距问题
    • 3.7 本章小结
  • 第四章 Flexbox 布局(已完结)
    • 4.1 Flexbox 布局原理
    • 4.2 弹性子元素的大小
    • 4.3 弹性布局的方向
    • 4.4 对齐、间距等细节处
    • 4.5 本章小结
  • 第五章 网格布局(已完结)
    • 5.1 构建基础网格
    • 5.2 网格结构剖析 (上)
      • 5.2.1 网格线的编号(下)
      • 5.2.2 网格与 Flexbox 配合(下)
    • 5.3 两种替代语法
      • 5.3.1 命名网格线
      • 5.3.2 命名网格区域
    • 5.4 显式网格与隐式网格(上)
      • 5.4.1 添加变化 (中)
      • 5.4.2 让网格元素填满网格轨道(下)
    • 5.5 子网格(全新增补内容)
    • 5.6 对齐相关的属性
    • 5.7 本章小结
  • 第六章 定位与堆叠上下文(已完结)
    • 6.1 固定定位
      • 6.1.1 创建一个固定定位的模态对话框
      • 6.1.2 在模态对话框打开时防止屏幕滚动
      • 6.1.3 控制定位元素的大小
    • 6.2 绝对定位
      • 6.2.1 关闭按钮的绝对定位
      • 6.2.2 伪元素的定位问题
    • 6.3 相对定位
      • 6.3.1 创建下拉菜单(上)
      • 6.3.2 创建 CSS 三角形(下)
    • 6.4 堆叠上下文与 z-index
      • 6.4.1 理解渲染过程与堆叠顺序(上)
      • 6.4.2 用 z-index 控制堆叠顺序(上)
      • 6.4.3 深入理解堆叠上下文(下)
    • 6.5 粘性定位
    • 6.6 本章小结
  • 第七章 响应式设计(已完结)
    • 7.1 移动端优先设计原则(上篇)
      • 7.1.1 创建移动端菜单(下篇)
      • 7.1.2 给视口添加 meta 标签(下篇)
    • 7.2 媒体查询(上篇)
      • 7.2.1 深入理解媒体查询的类型(上篇)
      • 7.2.2 页面断点的添加(中篇)
      • 7.2.3 响应式列的添加(下篇)
    • 7.3 流式布局
    • 7.4 响应式图片
    • 7.5 本章小结
  • 第八章 层叠图层及其嵌套
    • 8.1 用 layer 图层来操控层叠规则(上篇)
      • 8.1.1 图层的定义(上篇)
      • 8.1.2 图层的顺序与优先级(下篇)
      • 8.1.3 revert-layer 关键字(下篇)
    • 8.2 层叠图层的推荐组织方案
    • 8.3 伪类 :is() 和 :where() 的用法
    • 8.4 CSS 嵌套的使用
      • 8.4.1 嵌套选择器的使用
      • 8.4.2 深入理解嵌套选择器
      • 8.4.3 媒体查询及其他 @规则 的嵌套
    • 8.5 本章小结
  • 第九章 CSS 的模块化与作用域
    • 9.1 模块的定义
      • 9.1.1 模块和全局样式
      • 9.1.2 一个简单的 CSS 模块
      • 9.1.3 模块的变体
      • 9.1.4 多元素模块
    • 9.2 将模块组合为更大的结构
      • 9.2.1 模块中多个职责的拆分
      • 9.2.2 模块的命名
    • 9.3 CSS 的作用域
      • 9.3.1 CSS 作用域的就近原则
      • 9.3.2 划定作用域的边界
      • 9.3.3 CSS 中的隐式作用域
      • 9.3.4 关于 CSS 作用域与层叠图层
    • 9.4 CSS 模式库
    • 9.5 本章小结

http://www.kler.cn/a/418265.html

相关文章:

  • 深入理解AIGC背后的核心算法:GAN、Transformer与Diffusion Models
  • 【Android】组件化嘻嘻嘻gradle耶耶耶
  • 内网穿透步骤
  • CCF 第一届算法竞赛 CACC 考题回忆
  • Python小白语法基础18(文件操作)
  • sentinel使用手册
  • 安全见闻1
  • 冒泡排序算法介绍以及java实现
  • SQL调优分析200倍性能提升
  • Vue3+Echarts+echarts-wordcloud插件创建词云图
  • Docker命令总结
  • sys.stdout和sys.stdout.buffer
  • pnpm安装electron出现postinstall$ node install.js报错
  • 【中间件】Redis
  • 大模型开发和微调工具Llama-Factory-->量化1(GPTQ 和 AWQ)
  • Java并发07之ThreadLocal
  • fatal error:boostdesc_bgm.i:no such file or directory
  • 【学习笔记】基于RTOS的设计中的堆栈溢出(Stack Overflow)-第1部分
  • 前端项目中,通过命令行传入自定义参数
  • 排序-多语言
  • MySQL 利用JSON特性完成复杂数据存储和查询
  • 详解高斯消元
  • Axure PR 9 随机函数 设计交互
  • 每天五分钟机器学习:平行和重合
  • MySQL Workbench 数据库建模详解:从设计到实践
  • <三>51单片机PWM开发SG90和超声测距