CSS网页布局之 Grid布局完全解构

375 阅读12分钟

CSS的排版方式大致上包括Table、Float、FlexBox和Grid四种。 

Table是属于最古老的方式, 目前已经很少有人使用。 Float的排版方式曾经盛极一时,甚至用“DIV+CSS”去形容当时的这种新颖的排版方式,而FlexBoxGrid则是真正为了页面布局而设计的排版方式。 

FlexBox与 Grid的区别

最大的不同就是:

FlexBox是属于一维的排版方式:一个FlexBox容器只能控制一个方向,即水平方向或者垂直方向,如果需要控制另一方向则需要再添加一层FlexBox容器

Grid是属于二维的排版方式: 而Grid容器则可以一次控制两个方向,这样就可以直接定义容器内元素的位置了。


下面话不多说直接开始撸代码

首先创建一个Grid容器


Grid布局分为: display:griddisplay:inline-gridgrid下容器元素都是块级元素,而inline-grid则是行内元素

下面我们创建一个容器并指定grid属性。

html代码:

<div id="ruler"></div><div id="grid-container"></div>

css代码:

body{
    margin: 40px;
}
#ruler{
    position: absolute;
    top: 0;
    left: 0;
    width: 580px;
    height: 580px;
    background-image: url(https://codingstartup.com/assets/grid/grid-ruler.png);
    background-size: 580px 580px;
}
#grid-container{
    display: grid;
    width: 500px;
    height: 500px;
    background-color: #eee;
}


这样我们就得到一个带有标尺的grid容器。图上标尺为背景图,是为了能更好的理解Grid布局。

接下来我们再找标尺的定义将水平和垂直方向都分为5格,水平方向为column,垂直方向是rows


设定grid-template-rows属性:定义每一行的行高

css代码

#grid-container{
     display: grid;
     width: 500px;
     height: 500px;
     background-color: #eee;
     grid-template-rows: 100px 100px 100px 100px 100px;
}

grid-template-rows代表垂直方向的设定,设置5个100px,中间使用空格隔开,这样我们垂直方向就会分割出5个高度为100px的空间。


设定grid-template-columns属性:定义每一列的列宽

css代码

#grid-container{
     display: grid;
     width: 500px;
     height: 500px;
     background-color: #eee;
     grid-template-rows: 100px 100px 100px 100px 100px;
     grid-template-columns: 100px 100px 100px 100px 100px;
}

grid-template-columns代表水平方向的设定,同样设置5个100px,中间使用空格隔开,这样我们水平方向就会分割出5个宽度为100px的空间。

(1) repeat()函数

而有时候,重复写同样的值会非常的繁琐,尤其是网格较多的时候。这时,我们可以使用repeat()函数,简化重复的值。上面的代码用repeat()改写如下。

#grid-container{
            display: grid;
            width: 500px;
            height: 500px;
            background-color: #eee;
            grid-template-rows: repeat(5 100px);
            grid-template-columns: repeat(5 100px);
        }

repeat()函数接受两个参数,第一个参数是重复的次数(上例代码为5),第二个参数是所要重复在值(上例代码为100px)。

repeat()可以和正常的设定值混用,例如我们将一个容器的row分为5份,第1份为200px,其余每份为100px,这样可以大大提高灵活性。

grid-template-rows: 200px repeat(4 100px);


(2) auto-fill关键字

有时,网格的大小是固定的,但是容器的大小不确定。如果希望每一行(或每一列)容纳尽可能多的网格,这时可以使用auto-fill关键字表示自动填充。

grid-template-columns: repeat(auto-fill, 100px);

上面代码表示每列宽度100px,然后根据容器的宽度自动填充,知道容器不能放置更多的列。


(3) fr 关键字

为了方便表示比例关系,网格布局提供了fr关键字(fraction 的缩写,意为"片段")。有时,我们并不是所有的网格都要设置为绝对单位的,而是相对的,这时可以使用fr关键字表示比例。1fr即占有一份的意思,如果将上面代码中的100px都改为1fr的话,即各占5分之1的空间。

grid-template-columns: 1fr 1fr 1fr 1fr 1fr;

fr关键字可以和正常的设定值混用,例如我们将一个容器的row分为5份,第1份为200px,其余每份为1fr。这时容器会先将第1份空间设定为200px,再去把剩余的空间分为4份,平均分配。

grid-template-rows: 200px 1fr 1fr 1fr 1fr;

(4) minmax()

minmax()函数产生一个长度范围,表示长度就在这个范围之中。它接受两个参数,分别为最小值和最大值。

grid-template-columns: 1fr 1fr minmax(100px, 1fr);

上面代码中, minmax(100px, 1fr) 表示列宽不小于100px, 不大于1fr

(5) auto 关键字

auto关键字表示由浏览器自己决定长度。

grid-template-columns: 100px auto 100px;

上面代码中,  第二列的宽度,基本上等于该列单元格的最大宽度,除非单元格内容设置了min-width,且这个值大于最大宽度。




设定好grid容器之后,接下来我们就可以往里面添加一些元素了


添加元素

先在grid容器内添加两个div盒子,并设置背景颜色

html代码
<div id="grid-container">
   <div class="cell-1"></div>
   <div class="cell-2"></div>
</div>

css代码

.cell-1{
    background-color: blue;
}
.cell-2{
    background-color: yellow;
}


现在我们可以看到蓝色和黄色各占一格,这是在未定义元素的位置时预设的情况。

如果我们想将蓝色占据左上方的4格,也就是占据标尺中row的1-3和column的1-3,我们可以这样设置:将grid-row设置为1/3,grid-column设置为1/3。

再将黄色占据左下方的4格,也就是占据标尺中row的4-6和column的4-6,我们可以这样设置:将grid-row设置为4/6,grid-column设置为1/3。

css代码

.cell-1{
    background-color: blue;
    grid-row: 1/3;
    grid-column: 1/3;
}
.cell-2{
    background-color: yellow;
    grid-row: 4/6;
    grid-column: 1/3;
}




这样蓝色和黄色元素已经占据了对应的位置了,而当我们要调整元素在grid容器内的位置时只需要修改grid-rowgrid-colu的值即可:例如将蓝色的grid-row改为1/4,黄色的grid-column改为2/6,则会变成下图的效果:

css代码

.cell-1{
    background-color: blue;
    grid-row: 1/4;
    grid-column: 1/3;
}
.cell-2{
    background-color: yellow;
    grid-row: 4/6;
    grid-column: 2/6;
}




为什么在上方我们会先定义grid容器的row再定义column呢?原因在于grid-rowgrid-column有一个简写的方法grid-area

grid-area属性

接下来我们用grid-area 属性去设定蓝色元素

css代码

.cell-1{
    background-color: blue;
    /* grid-row: 1/4; */
    /* grid-column: 1/3; */
    /* 以上两行代码可以简写为以下一行代码 */
    grid-area: 1/1/4/3;
}


可以看到效果都是一样的,grid-area 的设置顺序是:grid-row的第一个值、grid-column的第一个值、grid-row的第二个值、grid-column的第二个值,也可以理解为‘坐标’,即左上角、右下角坐标

那么这个方法纯粹是为了介绍给大家知道具体是使用哪种属性因人而异,因为个人觉得grid-area的设定值不是很直观。


那么现在grid-rowgrid-column的设定值是由第几至第几 的意思,例如由第1至第3:1/3

但是我们在实际开发中布局的时候并不会像现在这样有一把标尺,让我们能一眼就看出来对应的数字,所以它还有一种写法是由第几开始延伸多少格 ,通过span关键字,span就是延伸的意思,例如蓝色元素的grid-column可以改写为:

css代码

.cell-1{
    background-color: blue;
    grid-row: 1/4;
    grid-column: 2/ span 3;
}


如果需要设置单元格之间的间隔则需要用到一下的属性。



grid-row-gap属性,grid-colunm-gap属性,grid-gap 属性

grid-row-gap属性设置行与行的间隔(行间距),grid-column-gap属性设置列与列的间隔(列间距)。

#grid-container {
  grid-row-gap: 20px;
  grid-column-gap: 20px;
}


这样我们每个单元格之间都会有20px的间隔。

grid-gap属性是grid-column-gapgrid-row-gap的合并简写形式,语法如下。

grid-gap: <grid-row-gap> <grid-column-gap>;   第一个参数是行, 第二个参数是列

所以我们上面的css代码可以简写成:

#grid-container {
  grid-gap: 20px;
}

而如果grid-gap省略了第二个值,浏览器认为第二个值等于第一个值。

根据最新标准,上面三个属性名的grid-前缀已经删除,
grid-column-gapgrid-row-gap写成column-gaprow-gapgrid-gap写成gap



grid-template-areas 属性

网格布局允许指定"区域"(area),一个区域由单个或多个单元格组成。grid-template-areas属性用于定义区域。

#grid-container {  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 300px 100px;
  grid-template-areas: 'h h h'
                       'n m m'
                       'f f f';
}
.head {    background-color: rgb(248, 35, 35);    grid-area: h}.nav {    background-color: rgb(253, 253, 24);    grid-area: n}.main {    background-color: rgb(70, 70, 243);    grid-area: m}.footer {    background-color: rgb(77, 250, 86);    grid-area: f}


通过配置区域, 我们可以快速搭建出一个经典的页面布局


grid-auto-flow 属性

划分网格以后,容器的子元素会按照顺序,自动放置在每一个网格。默认的放置顺序是"先行后列",即先填满第一行,再开始放入第二行,即下图数字的顺序。


这个顺序由grid-auto-flow属性决定,默认值是row,即"先行后列"。也可以将它设成column,变成"先列后行"。

#grid-container {    display: grid;    background-color: #999;    grid-template-rows: 100px 100px 100px;    grid-template-columns: 100px 100px 100px;    grid-gap: 5px;    grid-auto-flow: column;}

上面代码将grid-auto-flow 设置为columu 以后,顺序就变成下图数字的顺序




justify-items 属性,align-items 属性,place-items 属性

justify-items属性设置单元格内容的水平位置(左中右),align-items属性设置单元格内容的垂直位置(上中下)。

这两个属性的写法完全相同,都可以取下面这些值。

  • start:对齐单元格的起始边缘。
  • end:对齐单元格的结束边缘。
  • center:单元格内部居中。
  • stretch:拉伸,占满单元格的整个宽度(默认值)。

#grid-container {    display: grid;    width: 310px;    background-color: #999;    grid-template-rows: 100px 100px 100px;    grid-template-columns: 100px 100px 100px;    grid-gap: 5px;    grid-auto-flow: column;    justify-items: center;}


设置了justify-items: center; 就如上图所示。

place-items属性是align-items属性和justify-items属性的合并简写形式。

place-items: <align-items> <justify-items>;   第一个参数是垂直, 第二个参数是水平

下面设置一下place-items: start start; 就如下图所示。


如果省略第二个值,则浏览器认为与第一个值相等。


justify-content 属性,align-content 属性,place-content 属性

justify-content属性是整个内容区域在容器里面的水平位置(左中右),align-content属性是整个内容区域的垂直位置(上中下)。

这两个属性的写法完全相同,都可以取下面这些值。(下面的图都以justify-content属性为例,align-content属性的图完全一样,只是将水平方向改成垂直方向。)

  • start - 对齐容器的起始边框。  默认值
  • end - 对齐容器的结束边框。
  • center - 容器内部居中。
  • stretch - 项目大小没有指定时,拉伸占据整个网格容器。
  • space-around - 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与容器边框的间隔大一倍。
  • space-between - 项目与项目的间隔相等,项目与容器边框之间没有间隔。
  • space-evenly - 项目与项目的间隔相等,项目与容器边框之间也是同样长度的间隔。


place-content属性是align-content属性和justify-content属性的合并简写形式。

place-content: <align-content> <justify-content>  第一个参数垂直, 第二个参数水平
place-content: space-around space-evenly;

如果省略第二个值,浏览器就会假定第二个值等于第一个值。


justify-self 属性,align-self 属性,place-self 属性

justify-self属性设置单元格内容的水平位置(左中右),跟justify-items属性的用法完全一致,但只作用于单个项目。

align-self属性设置单元格内容的垂直位置(上中下),跟align-items属性的用法完全一致,也是只作用于单个项目。

这两个属性都可以取下面四个值。

  • start:对齐单元格的起始边缘。
  • end:对齐单元格的结束边缘。
  • center:单元格内部居中。
  • stretch:拉伸,占满单元格的整个宽度(默认值)。

下面是justify-self: start;place-self: center center 的例子。

.cell-1 {    text-align: center;    font-size: 28px;    justify-self: start;    background-color: rgb(248, 35, 35);}.cell-2 {    text-align: center;    font-size: 28px;    place-self: center center;    background-color: rgb(253, 253, 24);}


place-self属性是align-self属性和justify-self属性的合并简写形式。

place-self: <align-self> <justify-self>;

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






本文引用资料:

1. www.bilibili.com/video/BV1XE…

2. www.ruanyifeng.com/blog/2019/0…