本文摘自:please call me HR
so,first question? 啥是 grid 布局?
grid 布局是针对 Web 布局的一个升级版,首先,回想一下,我们写 HTML 的时候,一个一个 div 像搭积木一样,完成我们最后的网页。当然,我们还需要使用 CSS 来配置我们每个 DOM 元素的具体位置,比如 navbar,sidebar 等等。有时候还要用各种 trick 才能满足我们想要的布局结果。但为啥总感觉不爽... 我就只想要这个元素放到指定位置而已,有这么难吗?
有的
当然,你可以使用 absolute 来完成,但这样造成的性能损耗我就不多说了,问题是,你调位置估计就要哭在哪。。。为啥? 太复杂了。。。按照图形学来说,如果有一个坐标让我布局,那就好了。 so, grid 就这样诞生了。经历了 flexbox 的一维布局,grid 我们就可以用一句话表达:
grid 是网页的二维布局方式
ok, let's start。由于 grid 的支持性真的很渣。。。所以使用时需要额外开启实验室特性,在 Chrome 中,打开 chrome://flags 开启实验特性即可。首先,我们来了解一下关于 grid 的基本概念。
grid 概念
grid 的内容其实和 table,flexbox 差不多。相当于两者的结合产物。通常,直接通过 display:grid;
来使用。最最基本的格式为:
<div class="container" style="display:grid;">
<div class="item item-1"></div>
<div class="item item-2"></div>
<div class="item item-3"></div>
</div>
这里就包含了两个最基本的概念。
container 和 items
container 就是使用 display:grid
的 DOM。items 就是 container 包裹的一级子元素。记住:二级子元素就和 grid 没关系!
然后,剩下的就是和 table 类似的属性了。
line 和 cell
这个就比较好解释了,先看图吧:
这是 grid_line
这是 grid_cell
当然,还没完,接着就是 repeat cell 过后的理念。
track 和 area
track 相当于就是 行或者列。area 就是多个 cell 组成的面积。
这是 track
这是 area
grid 基本布局
grid 的强大之处在于,他可以将网页划分为很多小格子,而你可以将你的 DOM 随意的放在你想放的格子里面。还有一个必须要记住的点:
column, float, clear, 和 vertical-align 在 grid 布局中是没有效果的!
我们先来看个 demo:
请问,你能在 5min 之内实现下列布局吗?
word哥。。。在没有接触到 grid 之前,我最先想到的就是使用 flexbox 来实现。而且需要 8 个 div。而且尼玛就 5min。要是遇到这样的面试题,我估计就直接喷面试官了。。。MDZZ。 但,面试官总会显现他蜜汁微笑说,这,不,是,很,简,单,吗?
是的,使用 grid 布局,真的很简单。看下实际代码也就几行:
// HTML
<div id="container">
<div class="column-1">one</div>
<div class="column-2">two</div>
<div class="column-3">three</div>
<div class="column-4">four</div>
<div class="column-5">five</div>
</div>
// CSS 部分
body {
min-width: 550px;
}
#container{
height: 200px;
display: grid;
grid-template-columns:1fr 1fr 1fr 1fr;
grid-template-rows:1fr 1fr 1fr;
grid-template-areas:"one one two three"
"four four two three"
"five five five three";
}
.column-1{
grid-area:one;
background-color: #F8594C;
}
.column-2{
grid-area:two;
background-color: #FFA29B;
}
.column-3{
grid-area:three;
background-color: #318B98;
}
.column-4{
grid-area:four;
background-color: #E73123;
}
.column-5{
grid-area:five;
background-color: #ABE646;
}
完整的实例可以参考: grid 布局
可以说,grid 就是让你用张纸画几个网格,然后填充,然后网页就做好了。如果你想要动效的话,使用 animation 就 ok。啊~ 真简单。。。 接下来,我们来详细的看一下 grid 里面有哪些属性标签。权威指南请参考: MDN grid layout
grid 标签讲解
grid 的标签可以细分为两类:一类是属于 container,一类是数据 items。
各有:
-
container:
grid-template-columns
grid-template-rows
grid-template-areas
grid-template
grid-auto-columns
grid-auto-rows
grid-auto-flow
grid
grid-column-gap
grid-row-gap
grid-gap
justify-items
align-items
justify-content
align-content
-
items:
grid-column-start
grid-column-end
grid-row-start
grid-row-end
grid-column
grid-row
grid-area
justify-self
align-self
看起来蛮多的,不过细分下来就几个: template,auto,gap,布局(content/items)
这里,我们就按上面的分类来讲解。首先是 container 分类部分:
container
template
container 中的 template 有三种(还有一个是综合标签):columns,rows,areas。我们先来看下 columns 和 rows。
grid-template-columns/rows
基本格式为:
grid-template-columns: <track-size> ... | <line-name> <track-size> ... | subgrid;
grid-template-rows: <track-size> ... | <line-name> <track-size> ... | subgrid;
也就是说,该标签中属性还是蛮多的。我们简单介绍一下:
track-size:不论是 column 还是 row,都是用来定义行高/列宽。取值可以为 px,%,auto,fr。重点说一下 auto 和 fr。 auto 和 其他两个属性结合起来才有效,表示自动充满剩下的空间。 fr 就是 free space 的意思,用来表示是否均分剩下的空间。
line-name:用来设置行/列 line 的名称。这个结合 item 中的 grid-row 有效。不设置的话,默认为 1,2,3,4...
subgrid:嵌套 grid 时有效。暂不在讨论的范围之内。
看实例吧:
设置如下属性值:
.container{
grid-template-columns: 40px 50px auto 50px 40px;
grid-template-rows: 25% 100px auto;
}
可以得到:
相当于每个值都代表行/列宽,百分数的值相对于 container 的宽度来的。继续,我们加上 line-name 来试一试:
.container{
grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end];
grid-template-rows: [row1-start] 25% [row1-end] 100px [third-line] auto [last-line];
}
感觉定义了 line-name 之后,会有点复杂。我们可以这样记忆,值抽象为就是行/列,左右两侧就是线。这样感觉是不是好一点了?
fr 的话,就比较简单了,均分操作:
.container{
grid-template-columns: 1fr 1fr 1fr;
}
另外, css 还提供了一个 repeat 函数,来帮助我们快速书写同样格式的样式:
// 使用 repeat
grid-template-columns: repeat(3, 20px [col-start]) 5%;
// 等同于
grid-template-columns: 20px [col-start] 20px [col-start] 20px [col-start] 5%;
另外,我们还可以使用简写形式,将 columns 和 rows 写在一起。
// 基本格式就是: row / column / area
grid-template:repeat(4,1fr) / repeat(3,1fr);
接下来是 grid-template-areas
。该属性通常和 items 中的 grid-area
结合一起使用。
grid-template-areas
他的基本格式为:
grid-template-areas: "<grid-area-name> | . | none | ..."
"..."
记住,areas 写的时候,注意是可以分行写的,这点极其重要。因为这可以对应于每个网格的 name 。基本取值为:
grid-area-name:相当于给每个 cell 取名字,比如 header,footer,body 等等。
. : 将该单元格设置空值。就是啥也没有的意思。连名字也没有,那么就相当于将该 cell 设为 empty。
none:是真的啥也没有,当和 grid_name 混合使用时,和
.
没啥太大的区别。但关键在于,他通常用于单独定义的。
记住,该属性必须和 item 中的 grid-area
才有效果,具体的使用就是我上面的 demo:
#container{
height: 200px;
display: grid;
grid-template-columns:1fr 1fr 1fr 1fr;
grid-template-rows:1fr 1fr 1fr;
grid-template-areas:"one one two three"
"four four two three"
"five five five three";
}
.column-1{
grid-area:one;
background-color: #F8594C;
}
.column-2{
grid-area:two;
background-color: #FFA29B;
}
...
整体效果如: grid-template-area
gap
grid 中 gap 相关的有两个:grid-column-gap,grid-row-gap。这很好理解,就是用来设置行/列间隙。基本格式也是很简单:
grid-column-gap: <line-size>;
grid-row-gap: <line-size>;
line-size:基本 web 中的长度单位都可以使用,比如 px,vh,em,rem,auto 等等。不过比较遗憾的是,他不能设置每一个行/列间隔的大小。
比如:
.container{
grid-column-gap: 10px;
grid-row-gap: 15px;
}
另外还有一个综合单位就是: grid-gap。它其实就是上面两个的综合。基本形式为:
grid-gap: <grid-column-gap> <grid-row-gap>;
接下来我们来看一下 auto 系列。
auto
auto 包含的内容和 gap 差别不大,不过,他包含的是 3 个 tag:
grid-auto-columns: <track-size> ...;
grid-auto-rows: <track-size> ...;
grid-auto-flow: row | column | row dense | column dense
我们先说一下前两个: grid-auto-columns,grid-auto-rows
这两个属性,主要是用来弥补当元素放的位置超出 grid 时,在外部虚拟生成行/列的大小值。感觉有点难懂。。。这个的主要应用场景同样需要和 item 中的两个属性值:grid-column,grid-row 结合使用。这两个是干嘛的?他们是根据网格的线来设置元素的位置。
比如:
// 这个 container 只有 2x2 的布局结构
.container{
grid-template-columns: 60px 60px;
grid-template-rows: 90px 90px
}
想这样:
现在将一个 item-b 放到 2x5 的右下角位置上。即为这样:
然后设置 grid-column 和 grid-row 可以为:
grid-column: 5 / 6; // 第 5 条到第 6 条竖线之间
grid-row: 2 / 3; // 第 2 条到第 3 条横线之间
但这样的问题是,他虽然确实占了,但是那个 cell 是 0x0 的,相当于没有。。。那有啥用。所以,为了更加灵活的设置, grid 推出的 auto 系列,就有用了。这里,我们可以设置:
grid-auto-columns: 60px;
// 为啥不设 row?
// 因为根本就没超过 row 的范围。。。
ok,现在就变为一下的格式:
当然,如果你设置超出了 row 的话,那就适合 grid-auto-rows 即可。现在看一个比较拗口的属性:
grid-auto-flow
它主要是用来设置多余元素在剩下位置的排列顺序,重置排序。基本格式为:
// row 为默认值
grid-auto-flow: row | column | row dense | column dense
row:设置剩下的元素按照行顺序一次填充,如果超出,自动增加行。
column:设置剩下元素按照列顺序依次填充,如果超出,自动增加列。
dense:强制剩下元素从第一个还未排的 cell 开始。
现假设,我们有个 3x3 的布局:
初始样式为:
看一下 CSS:
// 这里设置的 3x3 布局。然后将第一个 item 放在第二个 cell 位置
#container{
height: 200px;
display: grid;
grid-template:repeat(3,1fr) / repeat(3,1fr);
grid-auto-flow:row;
}
.column-1{
grid-column:2;
background-color: #F8594C;
}
.column-2{
background-color: #FFA29B;
}
//...
然后,剩下的就会依次排开。Ok,现在我们切换为 column,他排列方式就变为:
然后我们再加上 dense
。最后的结果(column dense
)就变为:
感觉,这个属性还是挺复杂的,关键它的插入算法的机理并没有太清楚,而且也还在草案道中,所以,我们简单了解就好,不深究了。
最后就是 4 个定位布局的属性了。
justify-items
align-items
justify-content
align-content
items/content
items 相关是用来控制 cell 里面内容的分布位置和 flexbox 中的 align-items/justify-content 类似。
justify-items
justify-items 是用来控制 item 水平布局。基本格式为:
// stretch 是默认值
justify-items: start | end | center | stretch;
那它的实际效果是啥呢?
看几张图,估计就明白了。
justify-items: start;
效果为:
justify-items: center;
效果为:
剩下的 end 和 stretch 我就不赘述了。如果不是 stretch,它都是根据你元素中的文本内容进行自适应宽度的。 在 item 中使用 justify-self
可以控制独立 item 的布局位置。
align-items
align-items 就是用来控制 item 垂直布局。基本格式为:
// stretch 是默认值
align-items: start | end | center | stretch;
它的效果和 justify-items 很类似,同样看几个 demo:
align-items: start;
效果图为:
上下的我就不多说了。并且,在 item 中使用 align-self
可以控制独立 item 的布局位置。
剩下的还有两个:justify-content,align-content
content 相关
它俩做的工作差不多,和上述两个 tag 最大的区别在于,它们是用来控制整个 container 的布局。怎么说呢?
当使用 grid-template-rows/columns
设置行高/列宽时,如果全部使用的都是 px
并没有填充满时,那么contaienr 就会有一个块空出来。所以,为了解决这个问题,grid 就提出了 justify-content,align-content 这两个 tag。
基本格式为:
// start 为默认值
justify-content: start | end | center | stretch | space-around | space-between | space-evenly;
align-content: start | end | center | stretch | space-around | space-between | space-evenly;
这里,针对 justify-content 进行下讲解,另外一个是相似的只是排列方向是按纵向来进行排列的。先假设,我们通过 grid-template-columns
设置的 container 如下图:
分别添加属性测试:
justify-content: end;
放后
justify-content: center;
放前
justify-content: stretch;
拉伸
justify-content: space-around;
该属性的意思是,将多余的 space 均匀分给每一个 grid-item(左右都有)。
space-around
justify-content: space-between;
该属性的意思是,将多余的 space 均匀的分在 grid-item 之间,不包括前后。
space-between
justify-content: space-evenly;
该属性的意思是,将多余的 sapce 均匀的分在 grid-item 之间,包括前后。
space-evenly
基本上关于 container 的标签就已经说完了。下面我们来看看 items 相关(可少了。。。)
items
items 中的标签有 3 类:line,area,布局
line
在 grid 布局中,定位一个 DOM 的位置,有两种方式,一种是靠 grid-line,比如,指定你从哪一根开始,另外一种是靠 area,比如,将一个 DOM 放在 1,2,3 cell 中。这里,关于 grid-line 布局的设置属性有两个:行/列
grid-column: grid-column-start / grid-column-end;
grid-row:grid-row-start / grid-row-end;
里面基本的取值可以为:
<number> | <name> | span <number> | span <name> | auto
比如:
grid-column:1/3; // 将 DOM 放在 第一行到第三行之间。
number:指定第几根线,来决定放的位置。
name:根据 grid-template-columns 中命名的
grid-line-name
来决定放的位置。span <number>/<name>:相当于到...为止。通常结合 number 时,效果才能体现出来,比如:
1/span 2
。表示从第 1 根开始,到过 2 根线位置。最后就是1/3
。
比如:
grid-column:1 / col4-start;
grid-row: 2/span 2;
area
通过 area 布局的标签就一个:grid-area
基本格式为:
grid-area: <name> | <row-start> / <column-start> / <row-end> / <column-end>;
name:根据 grid-template-areas 设置的 cell 的别名。比如:header,foooter 等。
row-start/.../column-end: 和上面的 grid-column 一致。用线来框出具体的范围。
例如:
grid-area: header;
// 或者为:
grid-area: 1 / col4-start / last-line / 6
布局
在 container 中提到过,使用 justify-self,align-self 即可实现在 cell 中,content 的排列位置。常用取值为:
justify-self: start | end | center | stretch;
align-self: start | end | center | stretch;
具体的实现方式在 container 中我已经说过了,这里就不赘述了。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。