
未完待续
(在 CSS Grid 中)Rows/columns are invisible markers 行和列是不可见的标记。
想象停车场地面上画的线。 驾驶员可以按照这些线来停车,但实际上它们只是地上的符号。驾驶员可以自由决定如何使用它们。

CSS Grid 如此强大的原因在于,可以有选择地忽略网格结构。
直接跳过
implicit grid 隐式网格:不指定行和列时,默认为每个元素创建 1 个新行。

grid-auto-flow 可以改变隐式网格的流向。row(default), column

乍一看,它很像 flex-direction ,但有一个关键的区别。
Flexbox 真正独特的地方在于它有两个方向。通过将 flex-direction 从 row 翻转到 column ,我们可以更改哪一个轴是主轴,哪一个轴是交叉轴。
在 CSS 网格中,没有“主轴”或“交叉轴”之类的东西。这个概念不存在。
相反,CSS 网格有行和列。 行始终沿 “块block”轴 排列。在英语和其他水平语言中,这是垂直轴。行总是一层一层地堆叠。列始终沿 “内联inline”轴 (水平)排列。
CSS Grid 在这方面就像 Flow 布局。行沿着“块”轴分布,就像 Flow 中的块级元素一样。
更改 grid-auto-flow 并没有从根本上改变网格的方向;一切都保持不变,除了我们的网格将具有多列而不是多行。
测试题
<style>
.wrapper {
display: grid;
}
header {
display: inline;
}
.help-btn {
position: absolute;
bottom: 0;
right: 0;
}
</style>
<body>
<main class="wrapper">
<header>Hello World</header>
<button class="help-btn">Help</button>
</main>
</body>这三个元素实际使用的布局模式如下:

<main> :和 display: flex 类似,display: grid 也是对子元素生效的,父元素保持了原本的 flow 布局。<header>:display: inline 是一个仅在 Flow 上下文中有意义的声明。在当前这种情况下,它没有任何作用。我们可以删除它,但什么都不会改变。<button>:最容易犯错的情况,当我们指定 position: absolute 后,它已经脱离了文档流(”out of flow”)。对父网格来说,这个元素不存在。当我们说一个元素脱离文档流,真正的意思是该元素没有参与当前布局。显式定义网格。
定义列:grid-template-columns

上图指定一个 2 列网格,其中第一列占用 25% 的可用空间,第二列占用 75%。
与 Flexbox 不同,这些值不是“建议”,而是硬性限制。 对上面的网格,即使没有足够的空间容纳其内容,第一列还是这个宽度!
fr 单位如果出现了溢出,如何解决?


fr 单位指的是 “fraction”. 这有点像 Flexbox:第一列占用“1个单位”空间,第二列占用“2个单位”空间。但如果内容太宽,这个列会增长以容纳它。
上面的提到的空间指的是可用空间,例如:200px 2fr 1fr 会在去掉 200px 后将剩下的宽度分三份。

2列网格,7个孩子。网格隐式创建所需数量的行。行高尽可能小而能包裹住该行最高的元素,如图:


使用 grid-template-rows 显式指定行高。

gap: 行间距 列间距;

.calendar {
grid-template-columns: 250px repeat(5, 1fr);
}
repeat 最常用于创建多个 fr 单位,但它也可以接受其他任何单位,like repeat(4, 200px).
虽然是一些和 Flexbox 里相同的属性,但它们的工作方式不完全相同。
justify-*
CSS 网格中,列的默认行为是拉伸(stretch)以占据所有可用空间。通过设置 justify-content: center 可以让列居中。
上图第三个子元素具有最宽的自然宽度,因此整个列收缩到此宽度,并将此宽度用于其他元素。
同样,justify-content 可以指定为 start 和 end ;因为不在 Flexbox 中,不用加 flex- 前缀。另外,space-between, space-around, and space-evenly 也适用。
另外还有一个属性:justify-items 如图:

乍一看,这些列似乎有不同的宽度。不过在 Devtools 中它实际是这样:

通常,网格子元素拉伸到其列的整个宽度。一个放置在 100px 宽的列中的元素,自己也是 100px 宽的。而 justify-items 改变的就是这一点。
总结:
justify-content 应用于网格结构,改变了网格列。justify-items 应用于子元素,不影响网格形状。align-*
注意:上面的代码为网格指定了固定高度 300px ,否则 align-content 没有任何效果。我们需要在网格中留出一些可用空间才能看到效果。
同理,align-items 如此工作:

*-self让特定子元素推翻父元素的对齐方式。和 Flexbox 中的使用方式一样。
.wrapper {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
align-items: center;
justify-items: center;
height: 100%;
border: 2px solid;
}
/*
The last child should move to the
bottom-right corner of its cell,
instead of the center.
*/
.box:last-of-type {
align-self: end;
justify-self: end;
}
.box {
width: 80px;
height: 80px;
background: black;
}
html,
body {
height: 100%;
}
grid-areaCSS 网格的杀手级功能:命名网格区域并为其分配元素。
<style>
.wrapper {
display: grid;
grid-template-areas:
'sidebar header'
'sidebar main-content'; /* 给区域起名字 */
grid-template-columns: 250px 1fr;
grid-template-rows: 80px 2fr;
}
aside {
grid-area: sidebar; /* 使用这些名字 */
}
header {
grid-area: header;
}
main {
grid-area: main-content;
}
</style>
<div class="wrapper">
<aside>Aside</aside>
<header>Header</header>
<main>Main</main>
</div>
网格由轨道(Tracks)和线(Lines)组成。网格线如下图所示,而两条网格线之间的空间被称为轨道(无论行或列)。

通过指定 grid-column 和 grid-row 来确定子元素占据网格的位置。斜线不表示除号,只是一种分隔符(起始 / 结束)。这种方法是 grid-area 的语法糖。

若不写分隔符后面的内容,如 grid-column: 3 ,则默认占据一条轨道,与 grid-column: 3 / 4 等价。
注意 Devtools 标注出的网格的右侧和下侧的负值:这是这些线的另一个编号。负数编号可以用于这种场景:如上图,我想让盒子高度占满整个网格高度,写 grid-row: 1 / 5 当然可以完成任务。然而后来情况有变需要更改 grid-template-rows 至 6,则要同步更改 grid-row 以重新占满整个高度。如果一开始写作:grid-row: 1 / -1 那么无论父网格如何变化,它始终能占满。
在 Module 5 中提到了使用 min(), max() 和 clamp() 函数来控制一个值在给定的上下限之间。CSS Grid 有一个相似的函数:minmax()
<style>
.grid {
display: grid;
gap: 16px;
grid-template-columns:
minmax(50px, 1fr)
minmax(250px, 1fr);
}
</style>
<main class="grid">
<div class="card"></div>
<div class="card"></div>
</main>minmax 的心智模型:我们想要两个等宽的列(均为 1fr ),但第一列不应收缩到 50px 以下,而第二列不应收缩到 250px 以下。本质上,minmax 是一种给网格单元设置 min-width 和 min-height 的方法。
flexible unit 应该放最后。minmax(1fr, 250px) 不合法,因为 1fr 不是有效的“最小值”。
除了数字之外,repeat() 还接受特殊关键字。
假设我们有一些宽度正好为 150px 的 card. 希望用尽可能多的 150px 宽的列填充网格。使用 auto-fill 关键字:
<style>
.grid {
display: grid;
gap: 16px;
grid-template-columns: repeat(auto-fill, 150px);
}
</style>
<main class="grid">
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
</main>

改变尺寸,发现随着可用空间的增加,列数也在增加。不过,当宽度不是 150px 的倍数时,多出来的空白部分都挤在右侧,不好看。解决方法是加一句:justify-content: space-evenly; 让多余的空白平均分配到各个单元格之间。

更好的方法是结合 minmax 函数,效果一样:
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));大概用不上,先放一个(待补充)。
到目前为止,我们一直在使用最小宽度非常小的卡片(150px)。如果将上面 minmax() 中的 150px 改为 400px,这会导致较小屏幕上该卡片宽度一定会溢出。解决方法有两种:
.grid {
display: grid;
padding: 16px;
gap: 16px;
grid-template-columns: 1fr;
}
@media (min-width: 450px) {
.grid {
grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
}
}当视口较小时,我们选择只使用更简单的单列网格布局。
请注意,媒体查询有一个 50px 的缓冲区。 尽管我们的最小卡片宽度是 400 像素,但我还是将开关切换到 450 像素。这会增加足够的空间用于填充(总共 32 像素,每边 16 像素)和滚动条(10-15 像素,具体取决于操作系统)。
.grid {
display: grid;
padding: 16px;
gap: 16px;
grid-template-columns: repeat(auto-fill, minmax(min(400px, 100%), 1fr));
}min(400px, 100%) :100% 指的是 .grid 元素的宽度。在大显示器上 .grid 宽度可能为 800px,此时 100% 解析为 800px .min() 选择两个值中较小的一个,因此在大显示器上,此表达式返回 400px 。
在较小的屏幕上,100%可能只有 250px. 此时返回值为 100% 。
也就是说:
/* On large screens: */
.grid {
grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
}
/* On small screens: */
.grid {
grid-template-columns: repeat(auto-fill, minmax(100%, 1fr));
}那么这两种方法哪一种更好呢?
不受欢迎但真实的答案是,这取决于情况!
当我从事独立项目时,我倾向于采用流畅的方法,因为我已经使用这些技术有一段时间了,并且我对它们感到满意。
不过,当与许多其他开发人员一起工作时,我可能会采用响应式方法。大多数 JS 开发人员不太熟悉这些高级 CSS 技术(这也是我创建这门课程的部分原因!),而且我不想编写对我的同事来说难以理解的代码。
它类似于高级 JS 技术,例如递归。递归是一个强大的工具,但在某些情况下,使用更直接的迭代方法可能更明智,以便初级队友可以理解代码并为代码做出贡献。
截至作者编写教程的时间,只有 Firefox 支持此属性。
截至目前(2024.1.17)主流浏览器均已支持。
待补充
怎么做到每个格子外面套一层装饰分割线?

这是一个棘手的问题,因为没有任何方法可以使网格线可见 - 即使我们可以,它也不会正是我们想要的,因为有些格子跨越多个行/列。
一个使用 background-color 的聪明解决办法:https://play.tailwindcss.com/3jvA7sGfce
将一个元素在其父元素中水平和垂直居中:

Flexbox 出现前,这是一个众所周知的棘手挑战。下面是 Flexbox 的三行解决方法:
.wrapper {
display: flex;
justify-content: center;
align-items: center;
}在 CSS Grid 中,我们同样可以这样写。此外,当我们将 justify-content and align-content 设置为同一个值时,还有一个简写:place-content
<style>
.wrapper {
display: grid;
place-content: center;
}
</style>
<section class="wrapper">
<div class="box"></div>
</section>Modern CSS is pretty friggin cool.
待补充

待补充
如何实现以下效果,在较小的屏幕上给右边的图片一个水平滚动条:

可以看到,给 .image-list 设置的 overflow: auto 似乎并没有起作用。

下面的例子看起来更直观:假设这个box里放着动物图片。由于 fr 单位根据其内容自动调整宽度,第二列变得和 box 一样宽。

<style>
.grid {
display: grid;
grid-template-columns: 175px 1fr;
gap: 16px;
}
.box {
width: 1000px;
height: 200px;
background-color: peachpuff;
}
</style>
<div class="grid">
<div class="intro">
<h2>My Photos</h2>
<p>Here are some animals I saw on holiday:</p>
</div>
<div class="box-container">
<div class="box"></div>
</div>
</div>有两种解决方法:
overflow 移动到 Grid 的直接子级。理论如下:如果网格子级具有 overflow: auto ,它会授予列缩小到该元素的自然宽度以下的权限。但这不能递归地工作:它必须位于直接网格子级上,而不是后代上。
min-width :将 1fr 改为 minmax(0, 1fr)版权声明
① 本博客所有原创文章,除非另有特别声明,均采用CC BY-NC-SA 4.0/知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行授权。
② 本博客中,在文章内容之外使用的原创图片、动画、音频等多媒体素材的知识产权归属如下:
(i) 由博客作者独立创作的素材,其知识产权由博客作者单独所有;
(ii) 与他人合作创作的素材,其知识产权由博客作者与原创作者共同所有;
(iii) 对于特定素材,如有不同的版权归属,将在相应位置特别注明。
未经原作者或博客作者的明确授权,任何个人或组织不得在其他场合使用、复制、修改或传播这些素材。