Grid 布局系统
CSS Grid Layout Level 1
我们一直用传统的 CSS 布局我们的网页,但是这种布局并不是很方便,我们用 table,用 float,用 inline-block,等等方法,但是这些方法其实都算是无奈的 hack 方法,无法直接达到目的,而且还常常会产生一些别的问题。
Grid 布局系统是一种新的 CSS 布局系统,有强大的控制块及其内容的尺寸和位置的能力,跟 Flexible Box 布局系统不一样的是,Flexible Box 布局是以单条坐标轴方向进行布局的,但是 Grid 布局优化为二维布局,就是说内容可以在两个维度上进行对齐。Grid 是第一个专门为解决布局问题而开发 CSS 模块。
Flex 布局
Grid 布局
在 Grid 布局中,容器内的内容将通过定位并对准网格来布置的,网格就是一系列水平和垂直线的相交集合,它将网格容器的空间划分为网格区域,使网格元素(网格容器里的内容)可以为放置在该区域中。
这里有两组网格线,一组沿着 block 轴(column轴)延伸,一组沿着 line 轴(row轴)延伸。
Grid Lines 网格线
grid line
就是网格的水平和垂直分界线。网格线可以是 column 轴
或者是 row 轴
。
它们可以通过数字来指定,或者指定的名称来指定,网格元素就是根据参考着网格线的位置属性来决定位置的。
#grid {
display: grid;
grid-template-columns: 150px 1fr;
grid-template-rows: 50px 1fr 50px;
}
#item1 {
grid-column: 2;
grid-row-start: 1;
grid-row-end: 4;
}
/* equivalent layout to the prior example, but using named lines */
#grid {
display: grid;
grid-template-columns: 150px [item1-start] 1fr [item1-end];
grid-template-rows: [item1-start] 50px 1fr 50px [item1-end];
}
#item1 {
grid-column: item1-start / item1-end;
grid-row: item1-start / item1-end;
}
Grid Tracks 网格轨道
grid Track
,就是指两条相邻网格线之间的那部分空间,换句话说就是 grid column
和 grid row
的一个通用术语,每个网格轨道都被分配了一个尺寸设置,用来控制网格轨道的宽度或可以增长到多宽。相邻的网格轨道可以用grid-gap
属性分隔,也可以紧密相连。
Grid Cells 网格单元格
grid cells
是 grid row
和 grid column
的交集,它是定位网格元素的最小可参考单位。
#grid {
display: grid;
grid-template-columns: 150px 1fr; /* two columns */
grid-template-rows: 50px 1fr 50px; /* three rows */
}
Grid Areas 网格区域
grid areas
是用于布置一个或多个网格项目的逻辑空间,一个 grid area
由一个或多个 grid cell
组成, 并且必须由 4 条边界线包围。grid area
可以通过 grid-template-areas
属性被显式命名,也可以由其边界网格线隐式引用。使用 grid-placement
属性可以将 grid item
分配到某个 grid area
/* using the template syntax */
#grid {
display: grid;
grid-template-areas: ". a"
"b a"
". a";
grid-template-columns: 150px 1fr;
grid-template-rows: 50px 1fr 50px;
}
#item1 { grid-area: a }
#item2 { grid-area: b }
#item3 { grid-area: b }
/* Align items 2 and 3 at different points in the grid area "b". */
/* By default, grid items are stretched to fit their grid area */
/* and these items would layer one over the other. */
#item2 { align-self: start; }
#item3 { justify-self: end; align-self: end; }
https://codepen.io/bubupu/pen/vJbNqg
在同一个 grid area
里的 grid item
互相之间不会直接影响彼此的布局,然而间接地,具有固定尺寸的 grid item
会影响到 grid track
的大小(并且因此影响到 grid track
的位置),这又可以影响到另一个 grid item
的位置或大小。
Grid Container 属性
Name: | 'display' | |
---|---|---|
New Values: | grid \ | inline-grid |
这个属性将元素定义为 grid container
,并为其内容建立新的网格化上下文。
grid : 元素生成块级 grid container
inline-grid : 元素生成行内块级 grid container
column,float,clear 和 vertical-align 在 grid container
中都是无效的。
Name: | 'grid-template-columns', 'grid-template-rows' | ||
---|---|---|---|
Value: | none \ |
这个属性指定了分隔的 grid track
列表的尺寸和 grid line
的名称。
none : 表示没有明确指定的 grid track
[
breadth> ,
如果 flex 尺寸被 minmax()
包围,那么就会应用一个最小值 ,例如: minmax(auto,
max-content : 表示占据网格轨道的最大内容网格元素的尺寸
min-content : 表示占据网格轨道的最小内容网格元素的尺寸
minmax(min, max) : 定义大于或等于 min 且小于或等于 max 的大小范围,如果 max < min, 那么 max 的值会被忽略,minmax(min, max) 就等于 min,如果 max 值被设置为
auto : 最大值和 max-content
相同,最小值代表占用网格轨道的网格物体的最小尺寸(由最小宽度/最小高度指定)。
Example:
grid-template-columns: 100px 1fr max-content minmax(min-content, 1fr);
5条网格线被创建:
1.位于网格容器的开始边界
2.距离开始边界 100px
3.距离前一条线的距离等于剩下可用空间(网格容器的宽度减去非弹性轨迹的宽度)的一半
4.距离前一条线的距离等于这两条线之间的列里的最大内容网格元素大小。
5.距离前一条线的距离不小于两条线之间的列里的最小内容网格元素大小,且不大于可用空间的一半
如果非弹性的尺寸(100px,
max-content
,min-content
)的总和超过了网格容器的宽度,那么最后一条线的距离边界的距离就会这个总和值相等(相当于1fr
大小被解析为 0),如果总和小于网格容器的宽度,最后一条网格线将会正好落在网格容器的末端。
给网格线命名
虽然网格线可以通过数字索引来引用,但是给网格线命名可以使网格属性更容易理解和维护。可以在 grid-template-rows 和 grid-template-columns 属性中显示命名,或者通过 grid-template-areas 属性创建命名的网络区域来隐式命名网格线。
Example:
#grid { display: grid; grid-template-columns: [first nav-start] 150px [main-start] 1fr [last]; grid-template-rows: [first header-start] 50px [main-start] 1fr [footer-start] 50px [last]; }
重复行和列:repeat() 符号
repeat() 表示轨道列表的片段重复,让我们能以更紧凑的形式写重复的大量行或列
Example:
grid-template-columns: 10px [col-start] 250px [col-end] 10px [col-start] 250px [col-end] 10px [col-start] 250px [col-end] 10px [col-start] 250px [col-end] 10px; /* 与上面等价,更简便的书写方式*/ grid-template-columns: repeat(4, 10px [col-start] 250px [col-end]) 10px;
repeat() 语法
repeat( [
第一个参数表示重复次数,第二个参数表示重复内容,另外 repeat 还有几个限制:
- repeat() 符号不能嵌套
- 自动重复 (
auto-fill
和auto-fit
) 不能与内在或者弹性尺寸组合。
auto-fill 和 auto-fit
当重复次数被设置为 auto-fill
, 如果网格容器在对应轴线上定义了尺寸或最大尺寸,那么重复次数就是不会导致溢出网格容器的最大正整数。如果网格容器在对应轴线上定义了最小尺寸,那么重复次数就是满足最小尺寸的最小正整数。
Example
以下代码将创建尽可能多的25个字符的列,以适应窗口宽度。如果有剩余的空间,它将分布在25个字符的列之间。
body { display: grid; grid-template-columns: repeat(auto-fill, minmax(25ch, 1fr)); }
auto-fit
的行为与 auto-fill
一致,除了在网格部署好后,任何空白的重复网格轨道都会被折叠,一个空白的网格轨道就是不含任何网格元素的轨道(这会导致所有的轨道都被折叠,如果它们都是空的话)。
弹性尺寸:单位 fr
弹性长度
剩余空间的分布发生在所有非弹性轨迹的尺寸值达到最大值以后。从可用空间中减去这些行或列的尺寸,剩下的才是剩余空间,然后再将它按与弹性系数成正比分成弹性大小的行和列。
Name: | 'grid-template-areas' | |
---|---|---|
Value: | none \ |
这个属性用于指定命名网格区域,这个命名可以在 grid-placement 属性中被引用。grid-template-areas 还提供了网格的可视化,使网格容器的整体布局更容易理解。
none : 表示没有指定的网格区域,也没有指定的网格轨道( 但是网格轨道还是可以由 grid-template-columns 或 grid-template-rows 创建命名)。
grid-template-areas:
"<grid-area-name> | . | none | ..."
"...";
. 表示一个空的单元格
Example
.item-a { grid-area: header; } .item-b { grid-area: main; } .item-c { grid-area: sidebar; } .item-d { grid-area: footer; } .container { grid-template-columns: repeat(4, 50px); grid-template-rows: auto; grid-template-areas: "header header header header" "main main . sidebar" "footer footer footer footer"; }
上面的代码创建了四列宽三行高的网格。整个顶行由标题去组成,中间行由两个区域组成,一个空单元格和一个侧边区域组成,最后一行全部是页脚
声明中的每行都需要具有相同数量的单元格
我们注意到这里没有显式命名网格线,但当你使用这个语法的时候,实际上这个区域的两端的行会自动命名。
如果我们给一个网格区域命名为 foo,则该区域行和列的起始线名称会被命名为 foo-start,最后一行和最后一列的结束线会被命名为 foo-end。这意味着有些线条可能有会多个名字,比如最左边的这条网格线,就有三个名字:header-start,main-start 和 footer-start。
Name: | 'grid-template' | ||
---|---|---|---|
Value: | none \ | [ <'grid-template-rows'> / <'grid-template-columns'> ] \ | [ |
grid-template
属性是单个声明 grid-template-columns
,grid-template-rows
,grid-template-areas
这三个属性的简写。
none : 将所有三个属性设置为其初始值('none')
<'grid-template-rows'> / <'grid-template-columns'> : 将 grid-template-rows 和 grid-template-columns 分别设置为指定的值,并将 grid-template-areas 设置为 'none'。
grid-template: auto 1fr / auto 1fr auto;
/* is equivalent to */
grid-template-rows: auto 1fr;
grid-template-columns: auto 1fr auto;
grid-template-areas: none;
[
- 将 grid-template-areas 设置为列出的 string 列表
- 将 grid-template-rows 设置为跟随在 string 之后的
(如果缺少尺寸自动填充为 'auto'),并在每个尺寸的前后用命名的网格线拼接。 - 将 grid-template-columns 设置在斜杠之后的 track-list,或不指定。
grid-template: [header-top] "a a a" [header-bottom]
[main-top] "b b b" 1fr [main-bottom]
/ auto 1fr auto;
/* is equivalent to */
grid-template-areas: "a a a"
"b b b";
grid-template-rows: [header-top] auto [header-bottom main-top] 1fr [main-bottom];
grid-template-columns: auto 1fr auto;
Names: | 'grid-auto-columns', 'grid-auto-rows' |
---|---|
Values: |
如果一个网格项被放在没有用 grid-template-rows
或 grid-template-columns
显式指定指定尺寸的行或列中,那么隐式的网格轨道会被创建来保存它。grid-auto-columns
和 grid-auto-rows
属性用于指定这种隐式创建的轨道的大小。
#grid {
display: grid;
grid-template-columns: 20px;
grid-auto-columns: 40px;
grid-template-rows: 20px;
grid-auto-rows: 40px;
}
#A { grid-column: 1; grid-row: 1; }
#B { grid-column: 2; grid-row: 2; }
#C { grid-column: 1; grid-row: 2; }
#D { grid-column: 2; grid-row: 2; }
<div id="grid">
<div id="A">A</div>
<div id="B">B</div>
<div id="C">C</div>
<div id="D">D</div>
</div>
Name: | 'grid-auto-flow' | |||
---|---|---|---|---|
Value: | [ row \ | column ] \ | \ | dense |
Initial: | row |
没有显示指定放置位置的 grid item
会通过 grid 自动布局算法,被放置到 grid container
中的空闲空间。'grid-auto-flow' 属性控制了自动布局算法的工作原理,指定了被自动放置的项目在网格容器中如何流动。
- row : 告诉自动布局算法依次填充每行,根据需要添加新行
- column : 告诉自动布局算法依次填充每列,根据需要添加新列
- dense : 告诉自动布局算法尝试在网格尽早用更大
grid item
填充空洞,这个可能导致grid item
出现乱序
<section class="container">
<div class="item-a">item-a</div>
<div class="item-b">item-b</div>
<div class="item-c">item-c</div>
<div class="item-d">item-d</div>
<div class="item-e">item-e</div>
</section>
.container {
display: grid;
grid-template-columns: repeat(5, 60px);
grid-template-rows: repeat(2, 30px);
grid-auto-flow: row;
}
.item-a {
grid-column: 1;
grid-row: 1 / 3;
}
.item-e {
grid-column: 5;
grid-row: 1 / 3;
}
.container {
display: grid;
grid-template-columns: repeat(5, 60px);
grid-template-rows: repeat(2, 30px);
grid-auto-flow: column;
}
Name: | 'grid' | ||
---|---|---|---|
Value: | <'grid-template'> \ | <'grid-template-rows'> / [ auto-flow && dense? ] <'grid-auto-column'>? \ | [ auto-flow && dense? ] <'grid-auto-rows'>? / <'grid-template-columns'> |
在单个声明中设置所有以下属性的简写:grid-template-rows,grid-template-columns,grid-template-areas,grid-auto-rows,grid-auto-columns 和 grid-auto-flow,它也将 grid-column-gap 和 grid-row-gap 设置为其初始值,即使它们不能由此属性显式设置。
grid: auto-flow 1fr / 100px;
/* is equivalent to */
grid-template: none / 100px;
grid-auto-flow: row;
grid-auto-rows: 1fr;
grid-auto-columns: auto;
grid: none / auto-flow 1fr;
/* is equivalent to */
grid-template: none;
grid-auto-flow: column;
grid-auto-rows: auto;
grid-auto-columns: 1fr;
网格项属性
每个网格项都与一个网格区域(网格项所占据的相邻的网格单元的矩形集合)相关联。
网格项在网格区域中的位置由 grid postion
和 grid span
组成。
- grid position : 网格项在网格中的位置,可以是明确指定的,也可以是自动放置确定的。
- grid span :网格项占用的轨道数,网格项占据的轨道范围始终是确定的,如果无法确定,默认设为 1。
网格放置属性有以下几项:
grid-row-start
, grid-row-end
, grid-column-start
, grid-column-end
它们的简写属性:
grid-row
, grid-column
, grid-area
这些属性让用户通过提供以下六条信息的任何信息来指定网格项位置:
Row | Column | |
---|---|---|
Start | row-start line | column-start |
End | row-end line | column-end line |
Span | row span | column span |
指定一个维度上的 start,end 和 span 中的任意两个,就意味着第三个值的确定。
grid-area | grid-column | grid-column-start |
---|---|---|
grid-column-end | ||
grid-row | grid-row-start | |
grid-row-end |
.item {
grid-column-start: <line> | span <number> | span <name> | auto;
grid-column-end: <line> | span <number> | span <name> | auto;
grid-row-start: <line> | span <number> | span <name> | auto;
grid-row-end: <line> | span <number> | span <name> | auto;
}
: 网格线,可以是一个数字编号来引用或一个名称来引用 - span
: 网格项目跨越的轨道数量 - span
: 该项目将跨越轨道,直到遇到提供名称的网格线 - auto : 表示自动放置,自动跨度或默认跨度为1
Example
.item-a {
grid-column-start: 2;
grid-column-end: five;
grid-row-start: row1-start;
grid-row-end: 3;
}
.item-b {
grid-column-start: 1;
grid-column-end: span col4-start;
grid-row-start: 2;
grid-row-end: span 2;
}
如果不指定 grid-column-end / grid-row-end,默认情况下网格项将跨域一个轨道。
另外网格项是可以重叠的,可以使用 z-index 来控制它们的堆叠顺序。
grid-column 和 grid-row
grid-column
是 grid-column-start
+ grid-column-end
的简写
grid-row
是 grid-row-start
+ grid-row-end
的简写
.item {
grid-column: <start-line> / <end-line> | <start-line> / span <value>;
grid-row: <start-line> / <end-line> | <start-line> / span <value>;
}
Example
.item-c {
grid-column: 3 / span 2;
grid-row: third-line / 4;
}
如果没有声明 end line,默认情况下该项目将跨越1个轨道。
grid-area
grid-area
属性用于给网格项指定一个名称,引用 grid-template-areas
属性里创建的区域名称。
另外,这个属性也可以写成 grid-column-start
+ grid-column-end
+ grid-row-start
+ grid-row-end
的缩写
.item {
grid-area: <name> | <row-start> / <column-start> / <row-end> / <column-end>;
}
: 指定放置的网格区域名 / : 网格线,可以是一个数字编号来引用或一个名称来引用/ /
Example
#grid {
grid-template-areas: ". . . a a"
". . . a a"
". . . a a";
}
.item-d {
grid-area: a;
}
.item-d {
grid-area: 1 / col4-start / last-line / 6
}