Fork me on GitHub

Grid布局

grid布局是一种新的布局方案。传统布局使用浮动和定位,而grid布局可以像表格一样将页面容器分割成一块一块的区域,定义子元素的排布和位置。可以说是flex布局的升级版。

借用大神旭哥的话:

Grid布局就像是“分田种地”。故事是这样的,张老板是个程序员,省吃俭用攒了点小钱,然后老家因为城镇化建设,农村都没什么人,土地都荒废在那里,于是就承包了一块地,打算养养鱼,种种果树。承包的地方很挺大,如何划分土地就成了问题,于是张老板打算借助Grid布局来划分。

对于身为码农的我们来说,种地就对了!

兼容性

Grid布局是微软在2010年提出来的一种新的布局方式,到2016年的时候提交了该布局的草案。经过近几年发展,兼容性越来越好。

grid布局兼容性

引用自 Can I Use 。兼容火狐52+、谷歌57+等现代浏览器,IE10和11需要添加-ms-来实现兼容。

名词概念

Grid Container、Grid Items(网格容器、网格项)

元素应用 display: grid;即成为网格容器,它是所有网格项的父元素。

很好理解,下面这个例子,class为container的div设置了 display: grid;,container就是网格容器,里面的item都是网格项。

<style>
  .container{ display: grid; }
</style>
<div class="container">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
    <div class="item">4</div>
    <div class="item">5</div>
</div>

Grid Lines(网格线)

所谓的网格都是由横向和竖向的若干线交错产生的,这些线就是网格线。

熟知数学的我们知道,正常情况下,n行有n + 1根水平网格线,m列有m + 1根垂直网格线,比如三行就有四根水平网格线。

网格线是定义容器的时候产生的,和网格项没有直接的关系,网格项是直接存在于html中的,但是网格线正常看不到它。说白了网格线是虚拟的。

Grid Track(网格轨道)

两个相邻的网格线之间为网格轨道。

网格轨道的特点是能接触到网格容器的边缘。

Grid Cell(网格单元)

两个相邻的列网格线和两个相邻的行网格线之间的空间为网格单元,类似于excel中的单元格。

Grid Areas(网格区域)

四条网格线包围的地方称为网格区域,类似于excel中的合并单元格。

关键字

fr(剩余空间分配数)

fr单位被用于在一系列长度值中分配剩余空间,如果多个已指定了多个部分,则剩下的空间根据各自的数字按比例分配。

fr兼容性

gr(网格数)

目前未被w3c采纳,可以作为了解。


属性

介绍完概念,进入正题。

gird布局的属性可以分为两类:容器属性和项目属性。

容器属性分为这几类:

  • display:布局方式
  • grid-template:定义网格线的名称和网格轨道的尺寸大小
  • gap:定义网格项之间的间隙
  • items:定义网格单元内容的位置
  • content:定义整个内容区域在容器里面的位置
  • grid-auto:定义多余网格的大小
  • grid-auto-flow:定义网格项的放置顺序

项目属性分为这几类:

  • column / row:指定项目位于哪(些)条网格线
  • area:指定项目放在哪一个区域
  • self:指定网格单元内容的位置

下面来看具体的使用

容器属性

1. display

有三种取值:grid | inline-grid | subgrid

gird:生成块级网格
inline-grid: 生成行内网格
subgrid: 网格容器本身就是网格项(嵌套网格容器),此属性用来继承其父网格容器的行、列大小。(目前所有浏览器都不兼容)

注意,设为网格布局以后,容器子元素(项目)的float、display: inline-block、display: table-cell、vertical-align和column-*等设置都将失效。但是position是不会失效的。

2.1 grid-template-columns和grid-template-rows

grid-template-columns用来定义每一列的宽度,grid-template-rows用来定义每一行的高度。

.container{
    grid-template-columns: 40px 50px auto 50px 40px;
    grid-template-rows: 25% 100px auto;
}

实例1

上面这个例子,就是一个三行五列的网格布局。

  • grid-template-columns的取值可以是绝对长度(px、em)、百分比、auto、fr、函数。
  • auto表示由浏览器自己决定长度。
函数&关键字:

$minmax(min, max):$

  • 用来定义一个范围,最小值为min,最大值为max。
  • max可以设置为fr,min不可以。
  • 如果max值小于min值,则该值会被视为min值。
.container{
    grid-template-columns: 40px 50px minmax(50px, 2fr) 1fr 40px;
    grid-template-rows: 25% 100px auto;
}

$repeat(repeat, values):$

  • 表示轨道列表的重复片段,允许以更紧凑的形式写入大量显示重复模式的列或行。
  • 第一个值repeat可以是固定的数字(n),表示重复n次,也可以是auto-fitauto-fill,表示自动填充,容纳不下的放到下一行。
    例如:
/* css */
.container{
   width: 800px;
   height: 300px;
   display: grid;
   grid-template-columns: repeat(auto-fit, 200px);
   grid-template-rows: auto auto;
   gap: 5px;
}
<!--html-->
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>

repeat测试

这里有两点要注意:

  • 布局设置的是两行,最终由于单个轨道容纳不下,最终变成4行。多出的这两行可以用grid-auto-rows来进行设置,这个属性后面会讲到。
  • auto-fitauto-fill通常是没有区别的,只有在容器宽度大于子元素的最小宽度总和时才有显示区别。
    我们来把上面的例子稍微改动一下,
.container{
   grid-template-columns: repeat(auto-fill, minmax(50px, 1fr));
}

auto-fill关键字

我们再看一下auto-fit

.container{
   grid-template-columns: repeat(auto-fit, minmax(50px, 1fr));
}

auto-fit关键字

可以发现,使用auto-fill的网格宽度为52.5px,auto-fit的网格宽度为75.5px
这个值我们可以计算一下
假设一行有n个单元格,两个单元格之间的间隙是5
所以 $50n + 5(n - 1) = 800$,n ≈ 14.6,向下取整得到14
有了列数,假设单元格宽度为 $x$ 带入上面这个式子:$14x + 5*13 = 800$,得到单元格宽度为52.5px

由此可知

  • auto-fitauto-fill都会以最小的宽度创建单元格,创建完成以后,如果有多余的单元格,auto-fit会把这些多余的单元格均分给每一网格项,再重新创建单元格,而auto-fill不会。
  • 需要注意的是:只有在容器宽度大于子元素的最小宽度总和时才会这样,除此之外两者的显示是一样的。
网格线名称:

grid-template-columns属性里面,还可以使用方括号,指定每一根网格线的名字,方便以后的引用。
名字可以写多个,用空格隔开。

.container{
    grid-template-columns: [c1 r1] 40px [c2] 50px [c3] auto [c4] 50px [c5] 40px;
    grid-template-rows: 25% 100px auto;
}

grid-template-rows的用法与grid-template-columns完全一样。

2.2 grid-template-areas

areas是区域的意思,grid-template-areas用来给各个网格单元命名,就像给网格线命名一个道理。写法上类似于矩阵。

.container{
    grid-template-columns: 40px 50px auto 50px 40px;
    grid-template-rows: 25% 100px auto;
    grid-template-areas:
      'a a a b b'
      'c c d . e'
      'c c d . e';
}

上面这个例子将网格分为a、b、c、d、e五个区域。如果某些区域不需要利用,则使用"点"(.)表示。

需要注意:

  • 写法上分号的位置,最后单元格的末尾才加分号。
  • 多个同名的,跨越相邻行或列的单元称为网格区块(grid area)。非矩形的网格区块是无效的。
  • 网格区块会影响到网格线。每个区块的起始网格线,会自动命名为区块名-start,终止网格线自动命名为区块名-end。上面例子中,第一行第3、4列间的网格线自动命名为a-endb-start,水平网格线亦同理。
  • 网格的命名并不会马上影响网格项的显示,需要使用项目属性指定其位置才可以,项目属性下面会讲到。

2.3 grid-template

grid-template属性是grid-template-columns、grid-template-rows和grid-template-areas这三个属性的合并简写形式。
语法是 grid-template: <'grid-template-rows'> / <'grid-template-columns'>

.container {
  display: grid;
  width: 100%;
  height: 200px;
  grid-template: [header-left] "head head" 30px [header-right]
                 [main-left]   "nav  main" 1fr  [main-right]
                 [footer-left] "nav  foot" 30px [footer-right]
                 / 120px 1fr;
}

先写行属性,再写列属性,中间用 / 隔开,从易读性考虑,不建议这样写。

3. grid-gap

grid-row-gap 属性是用来设置网格行与行之间的间隙,grid-column-gap 属性是用来设置网格列与列之间的间隙。

.container{
   display: grid;
   grid-template-columns: repeat(auto-fit, 200px);
   grid-template-rows: auto auto;
   grid-row-gap: 20px;
   grid-column-gap: 10px;
}

上面的代码设置列间隙为10px,行间隙为20px。

grid-gap是 grid-row-gap 和 grid-column-gap的简写形式,语法如下:
grid-gap:<row-gap> <column-gap>
如果省略了第二个值,浏览器认为第二个值等于第一个值。

根据最新标准,上面三个属性名的grid-前缀已经删除,grid-column-gap和grid-row-gap写成column-gap和row-gap,grid-gap写成gap。
但是为了兼容浏览器,比如火狐52-61,还需要使用带有前缀的属性。

4.1. justify-items和align-items

justify-items 定义了网格布局中项目的水平对齐方式,align-items 定义了竖直对齐方式。

这个与flex布局的有些区别,flex布局的对齐方式分主轴和交叉轴,主轴方向的改变影响属性作用的方向。而grid布局是二维的,行列方向是固定的,所以说到 justify 一定就是指行(水平)方向,align就是指列(竖直)方向。

属性值:

  • start:内容与网格区域的左端对齐
  • end: 内容与网格区域的右端对齐
  • center: 内容位于网格区域的中间位置
  • stretch: 内容宽度占据整个网格区域空间(默认值)

justify-items属性示例
上图显示了justify-items不同取值的结果,align-items与justify-items效果一样,只是作用的方向不同。

4.2. place-items

place-items属性是align-items属性和justify-items属性的合并简写形式。
语法是 place-items: <align-items> <justify-items>;
如果省略第二个值,则浏览器认为与第一个值相等。

.container{
   display: grid;
   grid-template-columns: repeat(auto-fit, 200px);
   grid-template-rows: auto auto;
   place-items: center center;
}

有了这个属性,水平垂直居中就很容易了。

5.1. justify-content和align-content

justify-content定义了网格容器中,网格区域在水平方向上的对齐方式,align-content定义了网格区域在竖直方向上的对齐方式。

属性值比items要多:

  • start:网格区域与容器的左端对齐
  • end: 网格区域与容器的右端对齐
  • center: 网格区域位于容器的中间位置
  • stretch: 网格区域占据整个容器空间(默认值)
  • space-around:网格项之间设置等宽的间隙,与容器边框的间隙是项之间间隙的一半
  • space-between: 网格项之间设置等宽的间隙,与容器边框没有间隙
  • space-evenly:网格项之间和与容器边框设置等宽的间隙

justify-content属性示例

与items一样,上图显示了justify-content不同取值的结果,align-content与justify-content效果一样,只是作用的方向不同。

5.2. place-content

place-content属性是align-content属性和justify-content属性的合并简写形式。
语法是 place-content: <align-content> <justify-content>;
如果省略第二个值,则浏览器认为与第一个值相等。

.container{
   display: grid;
   grid-template-columns: repeat(auto-fit, 200px);
   grid-template-rows: 100px 100px;
   place-content: space-around space-evenly;
}

6. grid-auto-columns和grid-auto-rows

指定自动生成的网格轨道的大小。

当定义的网格不够容纳所有网格项,多出的网格项另起一行排列,或者给某一个网格项指定到定义好的网格区域的外部,这个时候,浏览器会自动生成多余的网格,以便放置项目。

grid-auto-columns和grid-auto-rows就可以用来定义这些自动生成的多余的网格的大小。

.container{
   width: 500px;
   height: 400px;
   display: grid;
   grid-template-columns: 40px auto 50px 40px;
   grid-template-rows: 200px auto;
   grid-auto-columns: 50px;
   grid-gap: 5px;
}
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>

如上面的代码所示,定义的网格是2行4列一共8个单元格,但是网格项有10个,所以最终生成的网格是3行4列,grid-auto-columns: 50px;让最后一行的行高为50px。

grid-auto-columns和grid-auto-rows的默认值为auto

7. grid-auto-flow

属性控制着自动布局算法怎样运作,精确指定在网格中被自动布局的元素怎样排列。
语法为 grid-auto-flow: [ row | column ] || dense

属性值

  • row: 指定自动布局算法按照通过逐行填充来排列元素,在必要时增加新行。(默认值)
  • column:指定自动布局算法通过逐列填充来排列元素,在必要时增加新列。
  • dense: 指定自动布局算法使用一种“稠密”堆积算法,如果后面出现了稍小的元素,则会试图去填充网格中前面留下的空白。

dense的意思即填充元素的时候,轮到一个元素了,发现这个格子放不下了,这个元素就被放到了新一行,如果没有dense的话这个格子就空着了,加上dense的话,这个格子就会找其它能放下的元素放在这里。
这样做会填上稍大元素留下的空白,但同时也可能导致原来出现的次序被打乱。

博主不建议使用隐式的网格,即不建议使子元素超出定义的网格区域,也不建议使用grid-auto-flow,尤其dense属性值,会让布局变得难以控制。

项目属性

1.1. grid-column-start和grid-column-end和grid-row-start和grid-row-end

这四个属性用来指定网格项在网格中的位置。从意思上就很明确。

  • grid-column-start:项目左边框的位置
  • grid-column-end:项目右边框的位置
  • grid-row-start:项目上边框的位置
  • grid-row-end:项目下边框的位置

可以指定的有网格线数字(1、2、3...的顺序)、网格线名称(之前命过名的话)、span(跨越)

语法为: <name> | <number> | span <number>

.container{
  width: 600px;
  height: 400px;
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-auto-rows: 80px 1fr 1fr;
  grid-gap: 10px;
}
.item {
  background: skyblue;
}
.toolbar{
  grid-column-start: 1;
  grid-column-end: 3;
}
.tree{
  grid-row-start: 2;
  grid-row-end: 4;
}
<div class="container">
  <div class="item toolbar">toolbar</div>
  <div class="item tree">tree</div>
  <div class="item table">table</div>
  <div class="item subtable">subtable</div>
</div>

上面的代码所示的就是一个典型的布局,通过定义toolbar元素和tree元素的开始结束位置,达到占用多个单元的目的。

使用span关键字也可以实现,span表示"跨越",即左右边框(上下边框)之间跨越多少个网格。

.toolbar{
  grid-column-start: 1;
  grid-column-end: span 2;
}
.tree{
  grid-row-start: 2;
  grid-row-end: span 2;
}

1.2. grid-row和grid-column

grid-row是grid-row-start和grid-row-end的简写形式。
grid-column是grid-column-start和grid-column-end的简写形式。

语法为:<start-line> / <end-line>

.toolbar{
  grid-column: 1 / span 2;
}
.tree{
  grid-row-start: 2 / span 2;
}

2. grid-area

grid-area属性指定项目放在哪一个区域。

我们肯定还记得前面的这个属性grid-template-areas,给容器划分区域并命名,命名完成以后,使用grid-area属性就可以指定项目放到哪里了。

还是刚才那个典型布局,这次我们用grid-area属性来试试。

.container{
  width: 600px;
  height: 400px;
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-auto-rows: 80px 1fr 1fr;
  grid-gap: 10px;
  grid-template-areas:
    "toolbar toolbar"
    "tree table"
    "tree subtable";
}
.item {
  background: skyblue;
}
.toolbar{
  grid-area: toolbar;
}
.tree{
  grid-area: tree;
}
<div class="container">
  <div class="item toolbar">toolbar</div>
  <div class="item tree">tree</div>
  <div class="item table">table</div>
  <div class="item subtable">subtable</div>
</div>

可以看到,效果跟刚才是一样的。

我们需要注意的是:

  • 我们给容器划分区域,但是网格是不变的。
  • 如果多个项目放在同一个位置,这些项目会重叠,可以使用z-index指定哪个在上面显示。使用这个功能实现选项卡的切换也很方便。

3.1 justify-self和align-self

justify-self设置元素中内容的水平对齐方式。align-self设置元素中内容的竖直对齐方式。

  • start:内容与网格项的左端对齐
  • end: 内容与网格项的右端对齐
  • center: 内容位于网格项的中间位置
  • stretch: 内容宽度占据整个网格项空间(默认值)

3.2 place-self

place-self属性是align-self属性和justify-self属性的合并简写形式。
语法为:<align-self> <justify-self>

.item {
  place-self: center center
}

如果省略第二个值,place-self属性会认为这两个值相等。

结束

以上就是grid布局的简单介绍~~

参考内容:
mdn api: https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Grid_Layout
阮一峰CSS Grid 网格布局教程:http://www.ruanyifeng.com/blog/2019/03/grid-layout-tutorial.html

posted @ 2020-09-07 15:54  gaiyb  阅读(2423)  评论(0编辑  收藏  举报