【CSS in Depth 2 精译_035】5.5 Grid 网格布局中的子网格布局(全新内容)

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

  • 第一章 层叠、优先级与继承(已完结)
    • 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.5 子网格布局 Subgrid](#5.5 子网格布局 Subgrid)
      • [5.5.1 子网格的其他配置项 Additional options](#5.5.1 子网格的其他配置项 Additional options)

《CSS in Depth》新版封面

译者按

学完 CSS 网格布局中的隐式网格(Implicit grid),这一节又迎来了一个非常实用的知识点:子网格(subgrid)。本节内容在 6 年前发行第 1 版时仅以一小段文字说明草草带过。经历了 6 年的技术沉淀,作者在第 2 版中索性另起一节,通过一个具体的案例,将子网格近年来的主流用法与最佳实践融入进来,最后还顺便提了一下尚在试验阶段的一个 CSS 新特性:砖石布局。窃以为这才是前端开发人员最应具备的职业素养:紧跟世界一流水平,熟悉业内最佳实践,只啃原汁原味的第一手资料。一起来先睹为快吧!

5.5 子网格布局 Subgrid

在前面的示例中,网格布局都只作用于 DOM 结构的两个层级:一是网格容器,二是其(直接)子元素。而对于某些设计,可能需要在更大层级范围内实现元素对齐。例如,要对齐同一祖先元素内的两个子元素,或者对它们设置相同的大小。这类设计的一个示例效果,如图 5.19 所示:

图 5.19 内部元素对齐的多张卡片布局效果

上述样式设计中,多张卡片都位于同一个网格内,因此水平方向排列整齐,高度也都相同。不仅如此,不同卡片的内部元素也实现了相互对齐:标题较短的两张卡片,通过增加顶部空间来与长标题那张对齐;每张卡片的正文段落相互间也实现了首行水平对齐;"Read more"(即"阅读更多")字样的超链接部分则实现了底边水平对齐。

要实现上述效果,最佳方案是利用一种全新的 CSS 特性,称为 子网格(subgrid。有了子网格,一个网格不仅能放入另一个网格,其网格元素还能放置在外层网格的网格线上。本例中,每张卡片都占据了三行网格空间,并且各自的内容都与其对应的行相互对齐。图 5.20 高亮标出了参与页面布局的网格及其网格间隙。

图 5.20 高亮标注的网格线与网格间隙效果图

这时,就能看清卡片本身及其内部元素在同一个网格布局里进行定位的全过程了。

说明

图 5.20 是页面在 Firebox 浏览器中显示、并通过开发者工具 DevTools 标注出网格行的效果截图。在大多数浏览器中,想要调试出类似的网格效果,只需要打开检查面板(Inspector pane),然后找到目标元素旁边一个小小的"grid"字样的标签,单击它即可。Flexbox 布局也支持类似的功能。

需要注意的是,子网格当前还是 CSS 新出的一个功能特性,并不像网格那样得到广泛支持。虽然子网格出现在 Firefox 及 Safari 浏览器中已经有些时日了,但 Chrome 和 Edge 浏览器也是到 2023 年底才对该特性予以支持。关于子网格在浏览器中的最新支持情况,请参阅:https://caniuse.com/css-subgrid

下面来演示上述布局的构建过程。首先创建一个新页面,并根据代码清单 5.12 更新页面 HTML 标记:

代码清单 5.12 三张作者信息卡片的网格布局 HTML 代码

html 复制代码
<!doctype html>
<html lang="en-US">
<head>
  <link href="styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
  <div class="author-bios"><!-- 主网格容器 -->
    <div class="card"><!-- 卡片元素 -->
      <h3>Sir Arthur Ignatius Conan Doyle</h3>
      <div>
        <p>
          A British writer and physician who created
          the fictional detective Sherlock Holmes.
        </p>
      </div>
      <div class="read-more"><a href="/conan-doyle">
        Read more
      </a></div>
    </div>
    <div class="card"><!-- 卡片元素 -->
      <h3>Mark Twain</h3>
      <div>
        <p>
          An American author famous for <i>The
          Adventures of Tom Sawyer</i> and
          <i>Adventures of Huckleberry Finn</i>.
          He has been called "the father of
          American literature."
        </p>
      </div>
      <div class="read-more"><a href="/mark-twain">
        Read more
      </a></div>
    </div>
    <div class="card"><!-- 卡片元素 -->
      <h3>Homer</h3>
      <div>
        <p>
          Author of the Greek epic poems <i>The
          Iliad</i> and <i>The Odyssey</i>.
        </p>
      </div>
      <div class="read-more"><a href="/homer">
        Read more
      </a></div>
    </div>
  </div>
</body>
</html>

如以上代码所示,实现该布局,需要重点处理好这三个层级的 DOM 元素对齐:

  1. 主网格容器:即 <div class="author-bios"> 元素;
  2. 各网格元素:即三个 <div class="card"> 元素;
  3. 卡片各自的子元素。

先来处理基础样式,包括背景色、间距、以及用于放置卡片的最顶层网格,如代码清单 5.13 所示。其中的样式可能除了个别网格声明还有点陌生(如果您正在熟悉网格布局)以外,其他大部分样式应该都已经很熟悉了:

代码清单 5.13 对作者卡片设置网格布局的样式代码

css 复制代码
body {
  background-color: #eee;
  font-family: Helvetica, Arial, sans-serif;
}
 
.author-bios {
  display: grid;  /* 声明网格容器 */
  grid-template-columns: repeat(3, 1fr);  /* 定义容器中的三个等宽网格列 */
  gap: 1em;
  max-inline-size: 800px;
  margin-inline: auto;
}
 
.card {
  padding: 1rem;
  border-radius: 0.5rem;
  background-color: #fff;
}
 
.card > h3 {
  margin-block: 0;
  padding-block-end: 0.5rem;
  border-block-end: 1px solid #eee;
}
 
.read-more {
  margin-block-start: 1em;
  text-align: right;
}

以上样式生效后,三张卡片就会在水平方向一字排开,看上去已经非常接近最终效果了(如图 5.21 所示)。之后就剩子网格的具体设置了。

图 5.21 子网格生效前,三张作者信息卡的对齐效果图

要在页面中添加子网格,必须先在网格元素中声明 display: grid,这样就在外层网格中创建了一个内部网格。接着,在该内部网格的 grid-template-rows 和/或 grid-template-columns 中使用关键字 subgrid,表示其使用的应该为父网格的网格线。

相关 CSS 样式如代码清单 5.14 所示。请将以下样式更新到本地样式表:

代码清单 5.14 为卡片内容设置子网格的样式代码

css 复制代码
.card {
  display: grid;  /* 设置该卡片为网格容器 */
  gap: 0;
  grid-row: span 3; /* 令卡片横跨三行 */
  grid-template-rows: max-content auto max-content; /* 为不支持子网格的浏览器设置回退方案,指定网格行尺寸 */
  grid-template-rows: subgrid; /* 使用父网格的网格行 */
  padding: 1rem;
  border-radius: 0.5rem;
  background-color: #fff;
}

.card > h3 {
  align-self: end; /* 令标题内容对齐到网格行的底部 */
  margin-block: 0;
  padding-block-end: 0.5rem;
  border-block-end: 1px solid #eee;
}

鉴于子网格仍是 CSS 一个较新的功能特性,这里特地为 grid-template-rows 提供了一套回退方案来效仿子网格的行为特征(该方案只能将三个"Read more"链接相对网格底边统一对齐,无法让标题部分相对各自的底边对齐)。还有一种备选方案,是将这些样式放到 CSS 特性查询语法中,检测当前环境对子网格的支持情况,例如:@supports (grid-template-rows: subgrid) {...}

译注

关于上述回退方案的实际效果,原书一笔带过。这里觉得有必要配一张截图,方便与子网格的实际对齐效果进行比较:

补图1:当浏览器不支持子网格功能、备选回退方案生效时的页面效果

本例演示了关键字 subgrid 将元素对齐到父网格行的具体方法,您也可以声明 grid-template-columns: subgrid 让元素根据父网格的列对齐,甚至同时对行与列对齐。此外,还可以在 DOM 树中延续这种写法,将子网格嵌套进另一个子网格中。

5.5.1 子网格的其他配置项 Additional options

子网格中的网格线编号、网格线名称以及网格区域名称均从父网格中继承而来,因此可以利用它们在子网格中放置元素。例如,以下样式会将所有卡片标题放在第二行:

css 复制代码
.card {
  grid-template-rows: subgrid [line1] [line2] [line3] [line4];
}

以上这些命名网格线,与前面 5.3.1 小节介绍的一样,它们的含义及用法与在普通网格上定义的网格线均相同。例如,声明 grid-row: line3 / line4 会将元素放置在第 3 条和第 4 条水平网格线之间的子网格中。

注意

未来可能出现的一个新网格特性功能,叫做 砖石布局(masonry layout) (译注:发音为 /ˈmeɪsənri/)。它是一种在相册场景下非常流行的布局方式,但需要借助 JavaScript 才能实现其效果。在砖石布局中,网格元素被放置在一系列宽度相等的网格列中,并且允许网格元素根据自身内容决定其高度,因此网格行不一定对齐。具体情况可以参考维也纳前端开发者 Manuel Matuzović 发表的这篇概述:Day 72: the masonry-auto-flow property
译注

为方便查阅,特将 5.3.1 节介绍命名网格线时自行补充的网格布局效果展示如下 :

补图2 除了最后一条水平网格线,其余都被命名为 "row"

对应的样式设置如下(详见 5.3.1 节:命名网格线):

css 复制代码
.container {
display: grid;
grid-template-columns:
 /* 分别给每条垂直网格线命名 */
 [left-start] 2fr
 [left-end right-start] 1fr
 [right-end];
/* 将水平网格线命名为 row */
grid-template-rows: repeat(4, [row] auto);
gap: var(--gap-size);
max-inline-size: 1080px;
margin-inline: auto;
}

header,
nav {
grid-column: left-start / right-end;
grid-row: span 1;
}

.main {
grid-column: left; /* 跨越 left-start 到 left-end 之间的区域 */
grid-row: row 3 / span 2; /* 从第三个命名网格线 row 开始放置元素,并跨越两个网格轨道 */
}

.sidebar-top {
grid-column: right; /* 跨越 right-start 到 right-end 之间的区域 */
grid-row: 3 / 4;
}

.sidebar-bottom {
grid-column: right; /* 跨越 right-start 到 right-end 之间的区域 */
grid-row: 4 / 5;
}

此外,关于上面提到的 砖石布局 ,也可以参考 MDN 的 线上官方文档,这里只补充其中一个示例效果图:

补图3 MDN 官方文档给出的一个砖石布局效果图



关于《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 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点1 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow1 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o1 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app
开心工作室_kaic2 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
刚刚好ā2 小时前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
沉默璇年3 小时前
react中useMemo的使用场景
前端·react.js·前端框架
yqcoder4 小时前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript
2401_882727574 小时前
BY组态-低代码web可视化组件
前端·后端·物联网·低代码·数学建模·前端框架
SoaringHeart4 小时前
Flutter进阶:基于 MLKit 的 OCR 文字识别
前端·flutter