Grid 布局笔记
HTML 代码实例结构:
<div class="wrapper">
<div class="box one">One</div>
<div class="box two">Two</div>
<div class="box three">Three</div>
<div class="box four">Four</div>
<div class="box five">Five</div>
</div>
CSS 基础样式:
.box {
padding: 10px;
}
.one {
background: bisque;
}
.two {
background: burlywood;
}
.three {
background: darkcyan;
}
.four {
background: darkorchid;
}
.five {
background: darksalmon;
}
1、Grid 布局基础概念
Grid 布局相当于一个二维网格布局,主要适用于页面的主要区域布局和小型组件。一情况下可以与 flex 布局进行结合使用实现很多布局形式。
1.1 声明 Grid 布局容器
在声明 Grid 容器时使用 display
属性进行声明,取值有 grid
和 inline-grid
。具体实例如下:
.wrapper {
display: grid;
}
1.2 声明 Grid 容器网格布局大小
在 Grid 容器中声明网格布局的话,主要使用 grid-template-columns
和 grid-template-rows
两个属性来声明。属性的值可以设置为 px、百分比和 fr。其中 fr 是声明网格的占比。具体实例如下:
/** 设置 3 列为200px的布局,多出的元素则是自动换行 */
grid-template-columns: 200px 200px 200px;
/** 设置 3 行为200px的布局,多出的元素则是按照内容高度来显示高度 */
grid-template-rows: 200px 200px 200px;
/** 假如每列都是同等宽度的话,可以使用 repeat 属性来简化代码,repeat 属性额可以用于 grid-template-rows */
grid-template-columns: repeat(3, 200px);
/** 使用 fr 实现 2: 1: 1 的布局 */
grid-template-columns: 2fr 1fr 1fr;
/** 混合使用单位 */
grid-template-columns: 100px repeat(2, 1fr) 200px;
1.3 grid-auto-rows 属性和 grid-auto-columns 属性说明
这两个属性主要在声明元素最大最小值和元素默认高度的时候使用。具体实例如下:
.wrapper {
display: grid;
grid-template-columns: repeat(3, 140px);
grid-auto-rows: minmax(100px, auto);
}
具体布局结果如下:
1.4 Grid 布局中的网格间距设置
网格间距主要是使用 grid-column-gap
和 grid-row-gap
两个属性。例如声明 10px 间距的网格布局。
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-column-gap: 10px;
grid-row-gap: 1em;
}
2、Grid 网格区域定位
在运用 Grid 布局的网格定位之前,需要先了解 Grid 布局中的网格线概念。
在 Grid 布局中,Grid 会为我们创建编号的网格线来让我们来定位每一个网格元素。例如下面这个三列两行的网格中,就拥有四条纵向的网格线。
Grid 网格区域定位与使用 grid-auto-rows 、 grid-auto-columns 两个属性来网格轨道布局不同,Grid 网格区域定位是通过网格线来定位的。简单说就是类似于电子表格的单元格合并。例如 One 元素合并 2 行 3 列、 Two 元素合并 2 行 1 列表,其余元素各占 1 个单元格,具体代码如下:
.wrapper {
display: grid;
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.box {
padding: 20px;
}
.one {
background: bisque;
grid-column-start: 1;
grid-column-end: 4;
grid-row-start: 1;
grid-row-end: 3;
}
.two {
background: burlywood;
grid-column-start: 1;
grid-row-start: 3;
grid-row-end: 5;
}
效果如下图:
通过上述的简单例子可以看出,Grid 网格区域定位其实就是使用 grid-column-start
、 grid-column-end
、 grid-row-start
和 grid-row-start
四个属性并结合网格线来进行区域的声明。
2.1 grid-column 属性说明
grid-column 属性是 grid-column-start
和 grid-column-end
两个属性的简写。用于指定网格项目的大小和位置,通过为它的网格位置贡献线条,跨度或不添加任何内容(自动)。
属性值设置方式如下:
-
数值 [ / 数值 ] : 声明开始和结束位置,结束位置没有声明的话,则会占一个单元格。假如数值为负数的话,则从显式网格的末端开始,反向计数。
具体实例如下:
.one { background: bisque; grid-column: 3 / -3; }
具体运行结果如下:
-
auto:网格设置为自适配宽度
-
span 与 数值 结合使用:span 主要是声明元素的跨度个数,例如元素跨度 2 个,具体代码如下:
.one { background: bisque; grid-column: span 2; }
具体运行结果如下:
-
开始位置 / span 合并数:从网格线 2 开始且跨度 2 个元素。
.wrapper { display: grid; display: grid; grid-template-columns: repeat(4, 1fr); } .box { padding: 20px; } .one { background: bisque; grid-column: 2 / span 2; }
具体运行结果如下:
-
span 合并数 / 结束位置:跨度 2 个元素且借结束位置为 4。
.wrapper { display: grid; display: grid; grid-template-columns: repeat(4, 1fr); } .box {**** padding: 20px; } .one { background: bisque; grid-column: span 2 / 4; }
具体运行结果如下:
2.2 grid-row 属性说明
grid-row 属性与 grid-column 属性一致。
3、Grid 自动定位
3.1 默认定位
如果没有为项目指定位置信息,它们就会把自己摆放在网格中,每个单元格中放一个。
3.2 自动定位的默认规则
默认的流向是按行排列项目,网格会首先尝试在第 1 行的每个单元格中摆放项目。如果已经通过 grid-template-rows 属性创建了其他行,网格就会继续把项目摆放到这些行中。如果在显式的网格中没有足够的行用来摆放所有的项目,隐式的新行就会被创建出来。
3.2.1 调整网格中隐式行的大小
在默认情况下,网格中被自动创建的隐式行的尺寸是自适应大小的,也就是说它们会包含所有属于它们的内容,而不会让内容溢出。
不过你可以通过 grid-auto-rows 属性来控制它们的大小。为了让所有的行都是 100 像素高,可以像下面这样做。
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
grid-auto-rows: 100px;
}
3.2.2 使用 minmax() 调整行的大小
也可以为 grid-auto-rows 设置 minmax() 值,这会让创建出的行保持一个最小尺寸,而且能够自动加高以适应更多的内容。
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
grid-auto-rows: minmax(100px, auto);
}
3.2.3 使用轨道列表调整行的大小
也可以向 grid-auto-rows 属性传入一个轨道列表,行的大小就会按轨道列表重复设置。在下例中,轨道列表声明了一个 100 像素的行和第二个 200 像素的行,当内容很多时网格就会自动创建足够多的隐式行来容纳内容。
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
grid-auto-rows: 100px 200px;
}
3.3 被自动定位的项目的顺序
网格中包含的多个项目可以混合定位,一些项目依靠明确的位置,而另一些则依靠自动定位。混合定位的用途在于,如果你有一个文档,其中部分项目已经定位,其他项目只要按顺序排列就行了,而无需为所有项目都指定绝对的位置。
3.3.1 为修改过顺序的文档排序
对没有指定网格位置的项目进行定位,在标准中被称为“为修改过顺序的文档排序”。这意味着如果完全使用 order 属性,项目的顺序将根据 order 属性重新排序,而不是它们在 DOM 中的顺序,要不然它们本来是按在 DOM 中出现的顺序排列的。
3.3.2 含有定位属性的项目
网格首先要做的是让每个项目都有一个位置。在下面的例子中,一共有 12 个网格项目,项目 2 和项目 5 已经通过使用基于线定位的方法确定了它们在网格中的位置。仔细观察网格空间中这两个已定位的项目和那些自动定位的项目。自动定位的项目将按在 DOM 中的顺序从已定位项目的前面开始摆放,虽然有两个项目已经事先定位好,但其他项目不是从已经定位的项目之后才开始摆放的。
<div class="wrapper">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
<div>Six</div>
<div>Seven</div>
<div>Eight</div>
<div>Nine</div>
<div>Ten</div>
<div>Eleven</div>
<div>Twelve</div>
</div>
.wrapper {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 100px;
gap: 10px;
}
.wrapper div:nth-child(2) {
grid-column: 3;
grid-row: 2 / 4;
}
.wrapper div:nth-child(5) {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
3.3.3 对占据多条轨道的项目的处理规则
在使用定位属性时仍然可以利用自动定位功能。在下面的例子中,有几个项目被设置为在行和列上都占据两条轨道,这是通过把 grid-column-end 和 grid-row-end 属性都设置为 span 2 实现的,这么写的意思是项目的开始线由自动定位规则确定,但是结束线将跨越两条轨道。
3.3.4 填充缺口
至此,除了我们明确定位过的项目,其他项目一般都会被网格自动处理并且保持它们在 DOM 中的顺序,这正是一般情况下我们想要的结果。比如你设计了一个表单,当然不想让标签和别的表单元素因为要填充缺口而使表单变得前后错乱。不过有时候要布局的项目并没有逻辑顺序,所以我们希望能够创建一种没有缺口的布局。
实现这个效果的方法是在网格容器的 grid-auto-flow 属性值中加入 dense 关键字。这和此前把网格流向改为列优先时设置值为 column 的是同一个属性,所以在列优先流向时,要设置 2 个值 grid-auto-flow: column dense。
经过以上设置,网格就会回填缺口,以前网格会遗留下缺口,而现在它会为此前的缺口找到适合它的项目,然后把项目从 DOM 中拿出来再放到缺口中去。对于已经重新指定过顺序的网格,这样做不会改变项目之间原有的逻辑顺序,比如对于 Tab 键的顺序仍然与文档的顺序相同。在后面的文章中我们会讨论网格布局潜在的可用性问题,此外你应该意识到,使用这个功能会让 DOM 中看到的顺序与实际显示的顺序不一致,它们两者之间的联系会被打破。
<div class="wrapper">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
<div>Six</div>
<div>Seven</div>
<div>Eight</div>
<div>Nine</div>
<div>Ten</div>
<div>Eleven</div>
<div>Twelve</div>
</div>
.wrapper div:nth-child(4n + 1) {
grid-column-end: span 2;
grid-row-end: span 2;
background-color: #ffa94d;
}
.wrapper div:nth-child(2) {
grid-column: 3;
grid-row: 2 / 4;
}
.wrapper div:nth-child(5) {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
.wrapper {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 100px;
gap: 10px;
grid-auto-flow: dense;
}
3.3.5 匿名网格项目
标准中还提到了匿名网格项目。当有一些字符串或文本被包含在网格容器中,但却没有被其他元素包装,它们就会被创建为匿名网格项目。下面的例子,假设容器的类 grid 设置了 display: grid 属性,那么网格中就有三个网格项目,第一个就是匿名项目,因为它没有用标签分隔,所以会被自动定位规则处理。另 2 个放在 div 中的项目,它们可以被自动定位,也可以通过网格的定位属性来定位。
匿名项目被自动定位是因为没有办法选定它们。所以如果在网格中有一些因故未被包装的文本,要小心它们可能会出现在网格的不可预期的位置,因为它们的位置完全靠自动定位规则来确定。