当前内容所在位置(可进入专栏查看其他译好的章节内容)
- 第一章 层叠、优先级与继承(已完结)
- 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.2 网格结构剖析
译者按
上一节,我们通过一个 2行 × 3列 的简单网格了解了网格布局中的两个核心概念 —— 网格容器(grid container)和网格元素(grid items),并认识了一个新的尺寸单位fr
(表示 fraction unit,即分数单位)。这一节,作者将结合上一章 Flexbox 布局使用的示例页,对网格布局的结构进行抽丝剥茧的深入讲解,一起来看看吧(由于内容相对较多,拟分为上篇、下篇两个部分发表,本篇为上篇)。
5.2 网格结构剖析
了解网格的各个部分非常重要。前面已经学习了 网格容器 和 网格元素,它们是网格布局的基本要素。还有四个重要概念如图 5.3 所示:
- 网格线(grid line):网格线构成了网格的框架结构,分水平网格线和垂直网格线两种,分别位于某行或某列的任意一侧。如果指定了间隙
gap
,那间隙就在网格线上。 - 网格轨道(grid track):它是两条相邻网格线之间的空间。网格可以有多个水平轨道(多行),以及多个垂直轨道(多列)。
- 网格单元(grid cell):它是网格上的一块单独空间,是水平和垂直网格轨道交叉重叠的部分。
- 网格区域(grid area):它是网格上的矩形区域,由一个或多个网格单元组成;该区域位于两条垂直网格线和两条水平网格线之间。
图 5.3 网格的组成部分
构建网格布局时会涉及到这些组成部分。例如,声明 grid-template-columns: 1fr 1fr 1fr
就能定义三个等宽且垂直的 网格轨道,同时还定义了四条垂直的的 网格线:一条位于网格的最左边;另外两条位于每个网格轨道之间,还有一条则位于网格的最右边。
上一章我们用 Flexbox 构建过一个示例页。不妨再回过头去看看当时的设计,考虑一下该怎样用网格布局再来实现一版。总体设计如图 5.4 所示,虚线标出了每个网格单元的位置。注意,某些区域跨越了好几个网格单元,即填充了更大的 网格区域。
图 5.4 用网格创建的网页布局效果图。虚线标出了每个网格单元的位置
上面的网格布局包含四行两列,其中前两个水平网格轨道分别是页面标题(Ink)部分和主导航菜单部分。主区域填满了第一个垂直轨道剩余的两个网格单元,而侧边栏的两个板块则分置于第二个垂直轨道剩余的两个网格单元内。
说明
布局设计无需填满每一个网格单元。在想留白的地方空出对应的网格单元即可。
使用 Flexbox 布局时,必须按照一定的方式去嵌套元素。第 5 章我们先用 Flexbox 定义了两列,然后在右侧边栏嵌套了另一个 Flexbox 来定义两个子板块所在的行(详见代码清单 5.1)。要用网格实现同样的布局效果,就得改改页面的 HTML 结构:将嵌套的 HTML 拉平,使得放置在网格内的每个页面元素都必须是主网格容器(main grid container)的子元素。新的 HTML 标记如代码清单 5.3 所示。创建一个新页面,并按以下代码更新页面内容(或者直接修改第五章中的示例页)。
代码清单 5.3 网格布局对应的 HTML 结构
<body>
<div class="container"><!-- 这里的“容器”即网格容器 -->
<header><!-- 每个网格元素都必须是网格容器的子元素 -->
<h1 class="page-heading">Ink</h1>
</header>
<nav><!-- 每个网格元素都必须是网格容器的子元素 -->
<ul class="site-nav">
<li><a href="/">Home</a></li>
<li><a href="/features">Features</a></li>
<li><a href="/pricing">Pricing</a></li>
<li><a href="/support">Support</a></li>
<li class="nav-right">
<a href="/about">About</a>
</li>
</ul>
</nav>
<main class="main tile"><!-- 每个网格元素都必须是网格容器的子元素 -->
<h1>Team collaboration done right</h1>
<p>Thousands of teams from all over the
world turn to <b>Ink</b> to communicate
and get things done.</p>
</main>
<div class="sidebar-top tile"><!-- 每个网格元素都必须是网格容器的子元素 -->
<form class="login-form">
<h3>Login</h3>
<p>
<label for="username">Username</label>
<input id="username" type="text"
name="username"/>
</p>
<p>
<label for="password">Password</label>
<input id="password" type="password"
name="password"/>
</p>
<button type="submit">Login</button>
</form>
</div>
<div class="sidebar-bottom tile centered stack"><!-- 每个网格元素都必须是网格容器的子元素 -->
<small>Starting at</small>
<div class="cost">
<span class="cost-currency">$</span>
<span class="cost-dollars">20</span>
<span class="cost-cents">.00</span>
</div>
<a class="cta-button" href="/pricing">
Sign up
</a>
</div>
</div>
</body>
新版页面将所有内容区域都变成了网格元素:标题、菜单(nav
)、主区域外加两个侧边栏。主区域和两个侧边栏都加上了 tile
样式类,因为它们都是白色背景,也有相同的内边距。
接着对新页面应用网格布局,并将各部分内容指定到对应区域。稍后我们将基于第五章的这版示例页引入大量新的样式,现在不妨先看看网格生效后的页面渲染情况,如图 5.5 所示。
图 5.5 基础网格布局生效后的示例页效果图
然后新建一张样式表,并关联到该页面。样式内容如代码清单 5.4 所示:
代码清单 5.4 最外层设置的网格布局样式
*,
::before,
::after {
box-sizing: border-box;
}
:root {
--gap-size: 1.5rem;
}
body {
background-color: #709b90;
font-family: Helvetica, Arial, sans-serif;
}
.stack > * + * {
margin-block-start: 1.5em;
}
.container {
display: grid;
grid-template-columns: 2fr 1fr; /* 定义两个垂直的网格轨道 */
grid-template-rows: repeat(4, auto); /* 定义四个大小为 auto 水平网格轨道 */
gap: var(--gap-size);
max-inline-size: 1080px;
margin-inline: auto;
}
header,
nav {
grid-column: 1 / 3; /* 垂直网格线从1号线跨越至3号线 */
grid-row: span 1; /* 恰好跨越一条水平轨道 */
}
.main {
/* 将其他网格元素定位到不同的网格线之间 */
grid-column: 1 / 2;
grid-row: 3 / 5;
}
.sidebar-top {
/* 将其他网格元素定位到不同的网格线之间 */
grid-column: 2 / 3;
grid-row: 3 / 4;
}
.sidebar-bottom {
/* 将其他网格元素定位到不同的网格线之间 */
grid-column: 2 / 3;
grid-row: 4 / 5;
}
.tile {
padding: 1.5em;
background-color: #fff;
}
.tile > :first-child {
margin-top: 0;
}
这段样式代码引入了很多新的写法,下面来逐个击破——
首先对 .container
设置了网格容器,并用 grid-template-columns
和 grid-template-rows
定义了网格轨道。因为列的分数单位分别为 2fr
和 1fr
,所以第一列的宽度是第二列的两倍。定义行的时候用到了一个新方法,即 repeat()
函数,用于简化多个网格轨道的声明。
声明 grid-template-rows: repeat(4, auto)
定义了四个高度为 auto
的水平网格轨道。这种写法相当于声明 grid-template-rows: auto auto auto auto
。轨道大小指定为 auto
,表示轨道尺寸将根据自身内容进行调整。
repeat()
简化表示法还可以用来定义不同的重复模式,比如 repeat(3, 2fr 1fr)
会重复三遍 2fr 1fr
,从而定义出六个网格轨道,重复的结果为 2fr 1fr 2fr 1fr 2fr 1fr
,效果如图 5.6 所示。
图 5.6 在网格模板定义里使用 repeat() 函数定制重复模式示意图
还可以将 repeat()
作为更长的模式的一部分进行简化。例如,grid-template-columns: 1fr repeat(3, 3fr) 1fr
定义了一个 1fr
宽的列,后面是连续三个宽度为 3fr
的列,最后又是一个宽 1fr
的列(即 1fr 3fr 3fr 3fr 1fr
)。不难发现,完整版的模板定义乍一看未必直观,因此才有了 repeat()
这样的简化写法。