grid布局指南

3,614 阅读9分钟

简介

Grid Layout是CSS的一种新的布局模型,它具有强大的功能来控制框及其内容的大小和位置。与单轴布局的Flexible Box Layout不同,Grid Layout可以在两个轴(列和行)中对齐内容。

通过一个示例学习grid语法

示例

设计一个如图的模块,划分为5个区域:游戏标题,排行榜,分数栏,游戏区域和控制区域。

  • 游戏区域的宽度与高度自适应
  • 排行榜的高度固定,当该区域有空余的位置时,其置于顶部
  • 控制区域在空间多余时置于中间

这是一个最简单的可以应用grid的示例,下面放上代码:

 <div id="grid">
    <div id="title">Game Title</div>
    <div id="score">Score</div>
    <div id="stats">Stats</div>
    <div id="board">Board</div>
    <div id="controls">Controls</div>
</div>
#grid {
  display: grid;
  grid-template-columns: 100px 1fr;
  grid-template-rows: 30px 1fr 30px;
  grid-template-areas:"title board" "stats board" "score controls";
  width: 300px;
  height: 500px;
}
#title {
  grid-column: 1; grid-row: 1;
}
#score {
  grid-area: score;
}
#stats {
  grid-column: 1; grid-row: 2; align-self: start;
}
#board {
  grid-column: 2; grid-row: 1 / span 2;
}
#controls {
  grid-column: 2; grid-row: 3; justify-self: center;
}

应用grid来布局我们可以轻松创建一个可以自适应多余空间的布局。这是grid的优点之一。

grid的还有一个特性就是grid可以让我们的布局与html语义结构解耦出来,不用根据html所定义的结构顺序来渲染,试我们可以在不同宽度的屏幕上展示不同的布局。

接下来一步步分析grid的语法:

生成grid容器

可以通过display:gird|inline-grid生成一个grid contaienr。grid container建立一个grid formatting context,特性与BFC类似,除了:

  1. float和clear属性对grid tem不会产生影响
  2. grid item的margins不会重叠
  3. vertical-align对grid-item无效...等。

这里需要注意的是这些特性只是存在GFC这一层,即对grid item这个对象有用,如果grid item这一层建立的是一个BFC,则该grid item里面的content还是遵从BFC进行渲染。

声明grid网格

可以通过 grid-template-rows,grid-template-columns 和 grid-template-areas三个属性来显示声明grid网格。

grid-template-*

grid-template-rows和grid-template-columns是生成网格线,网格线的索引是从显示声明的边缘网格线开始计数,左右两边分别从1和-1开始。当然我们也可以手动命名网格线,例子如下:

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];

grid-named-lines
一条网格线可以有多个名字。
grid-template-*的大致的语法如下:[ < line-names > ? < track-size > ]+ < line-names >?
其中track size就是两条线之间的空间,我们这里定义具体的长度:可以包括绝对长度单位,百分比长度单位,flexible长度(在grid当中是fr),max-content,min-content,minmax(min, max),auto等,这个在之后会做详细的讨论。
如果你需要定义的宽度是连续相等重复的,你还可以使用repeat(): repeat( [ < positive-integer > | auto-fill | auto-fit ] , < track-list > )

grid-template-areas

row和column相连网格线相互交叉组成grid cell,是放置grid item的最小单位。
grid-template-area就是给这些grid cell进行命名的。如上面的例子,我们给每一个grid cell都进行了命名。
grid-template-areas的值是由一系列的string组成,一个string代表一行,一行里面的命名通过空格进行区分。需要注意的是所有string里面的名字的个数需要相等。并且这些string里面所命名的grid cell有重复的名字,则需要他们在物理空间上是相连能组成一个更大的cell的,否则这个就会报错失效。
grid-template-areas会默认为这一个cell上面的线生成一个名字,如一个为foo的cell,生成横线名foo-start,foo-end,竖线名foo-start,foo-end。

grid-auto-*

当我们使用grid-template-areas来命名cell的时候,如果我们给的名字多于grid-template-columns和grid-template-rows组合生成的cell时,grid会自动生成新的网格线来提供cell。(当grid item多于grid cell的时候,也同样会自动生成新的网格线)
而网格线的宽度就是通过grid-auto-rows/grid-auto-columns定义的,默认为auto。我们可以给定一系列的长度单位。grid会循环使用这些长度单位来生成新的grid网格线。

声明排序顺序

当我们指定好grid的cell之后,grid item 会按照顺序放在cell之上。我们可以通过grid-auto-flow来指定flow的方向,默认为row,即items在grid的上面默认的flow方向是横着的,即一行放不下之后会flow到第二行去,而改为column之后则会默认竖着flow。还有一个值为dense。

声明间距

确认好网格线之后,我们还可以声明网格线之间的间距。通过gap(row-gap和 column-gap)属性来声明

声明布局方式

当我们定义的网格线范围小于grid 容器的时候,我们可以声明grid的布局方式。通过justify-content 和 align-content来定义。使用方法与flexbox中的类似。 比如值为end可以让整个content居于grid container的尾部。space-between可以让网格线分离,注意这同时会加大gap的距离。

声明对齐方式

我们可以在grid container上声明对齐方式,让grid item里面的content根据这个规则来对齐。通过justify-items和align-items来定义。

以上的属性都是在grid container这一层的,接下来介绍的是grid item这一层了。

放置items

通过这个图片上的属性值我们可以放置我们的items。比如

grid-row-start:1;
grid-row-end:3;
grid-column-start:2;
grid-column-end:3;

就是说将这个item放置到第一行开始第三行结束,第二列开始第三列结束所划分的这一个区域上。可以使用简写写法grid-row和grid-column,通过'/'来区分开始线和结束线。 具体我们可以通过3中写法来放置items:

  1. 放置到具名area上时我们可以使用grid-area。
  2. 可以通过线的数字索引来放置items。
  3. 可以通过线的名字来放置items。

如果有许多的线的名字重复的,可以通过数字来指定具体是这些相同名字的线的第几个

.six {
  grid-row: text 5 / text 7;
  /* Span between the 5th and 7th lines named "text". */
  grid-row: text 5 / span text 2;
  /* Same as above - start at the 5th line named "text",
     then span across two more "text" lines, to the 7th. */
}

这里有一个span关键字,默认item都是占据一个cell的,加上span之后,就指明该item占据多少cell。

如果不给item指定具体的放置位置,item则会根据flow规则默认占据接下来的一个cell

对齐

可以给特定item指定对齐方式。通过justify-self和align-self来定义。

grid的大致语法都介绍完了,通过上面的属性我们可以轻松生成一个grid容器。接下来我们研究下对于给定的网格线中的长度,grid容器是如何进行布局的。

Grid sizing

上面讲到我们通过grid-template-*来定义grid的网格线,该属性接受一系列的长度单位对grid进行切割。

绝对长度单位

最常见的比如说px,这种单位不受屏幕大小或字体的影响。如果grid-template-*上使用绝对长度单位,则在构建网格时,使用该绝对长度单位,并且不会进行flex。即使是有空余的空间或超出grid的范围。

display: grid;
grid-template-columns: 30px 30px;
grid-template-rows: 30px 30px 30px;
width: 50px;
height: 500px;

相对长度单位和百分比

这种单位都是相对于某一个参考值进行缩放,比如说rem就是根据根字体进行计算的。这种单位在布局中,在使用之前都是先计算出一个computed value的,因此在grid的布局中他们的值一开始就定下来了。因此布局规则与绝对单位长度的一样

min-content

顾名思义,就是说根据该item里面的的不可再切割的最小content来确定宽度。比如说一个item里面的内容是’i am superstar’,则就是根据superstar的宽度来进行布局

max-content

就是根据item里面的content的宽度就行布局。布局是宽度已经是确定了的,所以规则跟绝对长度单位一样,不会进行flex。

fit-content()

fit-content()里面接受一个长度单位,就是说如果item里面的content宽度没有超过该值的时候通过max-content进行布局,超过了话就用该值就行布局

上面介绍的这些都是在布局前就已经确定了一个长度单位了的,不会进行flex,接下来介绍的这些值是会进行flex的。

首先需要了解一下grid的布局规则,grid的在布局的时候宽度是从小到大的来进行计算的(这一点与flexbox不同)。当我们使用一些flexible单位时,计算规则是会去找该item的min-content的宽度,并将这个宽度作为flex-basis来进行grow

minmax()

接受两个参数,最小宽度和最大宽度,由于这个函数声明了最小宽度所以grid直接使用该值作为flex-basis,如果grid还有剩余空间则会进行grow,但是grow的时候不能超过定义的最大宽度。

fr

flexible单位,取min-content为最初始宽度,如果有剩余空间则进行grow。

Auto

是最后进行grow的单位,如果上述都进行grow了之后还有空间,则auto进行grow。

参考资料

css-grid-1
understanding-sizing-css-layout