Grid布局

101 阅读8分钟

grid布局

grid布局就是网格布局,虽然我们平常用得少,基本都是用flex布局,但是其实有些地方使用grid布局还是挺不错的,而且grid在处理多行行列二维布局的时候尤为方便,尤其是移动端、或者整体布局。

转为grid

我们知道我们css盒子一般分为块级、行内块、行内元素三种,而我们想转换他们的时候,就要使用display,或者我们使用flex布局的时候,也要使用display将其转为弹性盒子。而grid网格布局也是这样的。将其他盒子转为网格布局使用display有两个选项,一个是grid,一个是inline-grid

  • display:grid;是将盒子转为块级的网格布局;
  • display:inline-grid;是将盒子转为行内块的网格布局。

行与列

既然grid主要是处理二维的,那么二维是有许多行与列组成的,那么grid的行与列咋定义呢?

  • grid-template-columns:定义列
  • grid-template-rows:定义行

他们的样式属性都是一样的。他们可以使用具体的像素值px,也可以使用百分比,还可以使用fr和auto。

假如我们定义一个3行3列的九宫格:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin:0;
        }
        #box {
            width: 600px;
            height: 600px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns: 200px 200px 200px;
            grid-template-rows: 200px 200px 200px;
        }
    </style>
</head>
<body>
    <div id="box">
​
    </div>
</body>
</html>

image.png

我们发现现在这个div盒子已经是3*3的九宫格布局了,其中每一个格子就是200px * 200px;

我们还可以使用百分比布局,百分比布局就是按照本身盒子宽高为基准的。Emm,这个没啥好说的。

fr这个单位的意思和flex布局中的flex-grow的放大因子类似(计算方法类似)。都是将剩余空间进行再分配。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin:0;
        }
        #box {
            width: 600px;
            height: 600px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns: 1fr 1fr 1fr;
            grid-template-rows: 200px 200px 200px;
        }
    </style>
</head>
<body>
    <div id="box">
​
    </div>
</body>
</html>

image.png

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin:0;
        }
        #box {
            width: 600px;
            height: 600px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns: 1fr 2fr 1fr;
            grid-template-rows: 200px 200px 200px;
        }
    </style>
</head>
<body>
    <div id="box">
​
    </div>
</body>
</html>

image.png

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin:0;
        }
        #box {
            width: 600px;
            height: 600px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns: 100px 2fr 1fr;
            grid-template-rows: 200px 200px 200px;
        }
    </style>
</head>
<body>
    <div id="box">
​
    </div>
</body>
</html>

image.png

我们发现上面情况,得到的结果都不一样。

第一种情况是没有指定列的宽度,全部使用的是1fr,那么该盒子本身的宽度是600px,那么就将600px平分为3份,每一份的值就是600/3 = 200px。

第二种情况是将盒子分为3列,但是是将盒子分为了4份,那么每一份就是600/4 = 150px。而第一列和第三列占一份,那么他们的宽度就是150px,而第二列占了两份,那么它的宽度就是300px。

第三种情况是将盒子分为3列,但是第一列的宽度100px已经已知了,那么就将剩下的500px平分为3份,每一份就是500/3,而第二列占两份,第三列占1份。

此外:还可以使用auto;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin:0;
        }
        #box {
            width: 600px;
            height: 600px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns: 100px auto;
            grid-template-rows: 200px 200px 200px;
        }
    </style>
</head>
<body>
    <div id="box">
​
    </div>
</body>
</html>

image.png

auto的意思就是将剩余空间占满的意思,其实一般使用auto还是用得少,这种情况下用1fr就可以了。

repeat函数

此外我们还可以在grid-template-columns和grid-template-row中使用repeat函数。

repeat函数的意思就是重复的意思,它有两个参数:

  • 第一个参数:重复的次数
  • 第二个参数:如果是一个值,就是每次的宽度(高度)。如果是多个值,就是重复的几行或几列。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin:0;
        }
        #box {
            width: 600px;
            height: 600px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns: repeat(2,50px 200px);
            grid-template-rows: repeat(3,1fr);
        }
    </style>
</head>
<body>
    <div id="box">
​
    </div>
</body>
</html>

image.png

我们发现我们这里就是一个3行4列的网格。

因为grid-template-rows: repeat(3,1fr);表示一个3行,每一行为1fr。

grid-template-columns: repeat(2,50px 200px);中的repeat(2,50px 200px);表示重复2次,每一次就是宽为50px和宽为200px的2列。

所以最后就成了3行4列。

gap

  • grid-column-gap:列与列之间的距离
  • grid-row-gap:行与行之间的距离
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin:0;
        }
        #box {
            width: 600px;
            height: 600px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns: repeat(3,1fr);
            grid-template-rows: repeat(3,1fr);
            grid-row-gap:50px;
            grid-column-gap:50px;
        }
    </style>
</head>
<body>
    <div id="box">
​
    </div>
</body>
</html>

image.png

每行之间有50px的距离,每列之间有50px之间的距离。

grid-template-areas

通过引用grid-area属性指定的网格区域的名称来定义网络模板,重复网格区域的名称会使内容扩展到这些单元格.(其实就是给每一个单元格一个名字

<!DOCTYPE html>
<html lang="en"><head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }
​
        #box {
            width: 600px;
            height: 600px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns:  1fr 1fr 1fr ;
            grid-template-rows:  1fr 1fr 1fr;
            grid-template-areas: "a b c"
                                 "d d d"
                                 "e f f";
        }
    </style>
</head><body>
    <div id="box">
        
    </div>
</body></html>

image.png

grid-line线

其实我们在定义了行与列之后,网格盒子会自动给我们的每一行与每一列自动添加一条线。

#box {
            width: 600px;
            height: 600px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns: repeat(3,1fr);
            grid-template-rows: repeat(3,1fr);
        }

image.png

也就是说,第一行就是在1和2之间,第二行就是3和4之间,以此类推...

此外,我们也可以自己给每一条线重新命名。重新命名是在定义行与列的时候定义的。

   #box {
            width: 600px;
            height: 600px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns: [line1] 200px [line2] 200px [line3] 200px [line4];
            grid-template-rows: [first] 200px [second] 200px [third] 200px [last];
        }

image.png

(不过我还是喜欢使用默认的数字哈哈~)

网格的使用

现在我们是创建好了网格,但是我们要怎么使用这个网格呢?我们怎样把我们需要的元素填充到里面呢?

默认填充

一般情况下,我们写的元素会默认的一行一行的进行填充的,且默认填充一个网格。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin:0;
        }
        #box {
            width: 600px;
            height: 600px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns:  200px  200px  200px ;
            grid-template-rows: 200px  200px  200px ;
        }
        .item {
            background-color: red;
            color: #fff;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 20px;
            box-sizing: border-box;
            padding: 20px;
            background-clip: content-box;
        }
    </style>
</head>
<body>
    <div id="box">
        <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>
</body>
</html>

image.png

使用grid-line填充

我们也可以指定某个元素在网格中的位置,以及它占用的网格数量。

<!DOCTYPE html>
<html lang="en"><head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }
​
        #box {
            width: 600px;
            height: 600px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns:  200px  200px  200px ;
            grid-template-rows:  200px  200px  200px ;
        }
​
        .item {
            background-color: red;
            color: #fff;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 20px;
            box-sizing: border-box;
            padding: 20px;
            background-clip: content-box;
        }
​
        .item:nth-child(1) {
            grid-row-start: 1;
            grid-row-end: 4;
            grid-column-start: 1;
            grid-column-end: 2;
        }
​
        .item:nth-child(2) {
            grid-row-start: 1;
            grid-row-end: 2;
            grid-column-start: 2;
            grid-column-end: 4;
        }
        .item:nth-child(3) {
           grid-row: 2 / 4;
           grid-column: 2 /4 ;
        }
    </style>
</head><body>
    <div id="box">
        <div class="item">1</div>
        <div class="item">2</div>
        <div class="item">3</div>
    </div>
</body></html>

image.png

我们发现,我们可以使用grid-row-start和grid-row-end来指定我们这个元素的位置和大小。

.item:nth-child(1) {
            grid-row-start: 1;
            grid-row-end: 4;
            grid-column-start: 1;
            grid-column-end: 2;
        }

它的意思是它从行的第一条线开始填充,到第四条线填充结束;然后再从列的第一条线开始填充,到列的第二条线结束填充。

grid-row和grid-column是简写形式。

grid-row:grid-row-start / grid-row-end;

grid-column: grid-column-start / grid-column-end;

当然,他也可以配合我们自定义的线一起使用。

<!DOCTYPE html>
<html lang="en"><head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }
​
        #box {
            width: 600px;
            height: 600px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns: [line1] 200px [line2] 200px [line3] 200px [line4];
            grid-template-rows: [first] 200px [second] 200px [third] 200px [last];
        }
​
        .item {
            background-color: red;
            color: #fff;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 20px;
            box-sizing: border-box;
            padding: 20px;
            background-clip: content-box;
        }
​
        .item:nth-child(1) {
            grid-row:second/third;
            grid-column: line2/line3;
           
        }
    </style>
</head><body>
    <div id="box">
        <div class="item">1</div>
    </div>
</body></html>

image.png

使用grid-area填充

<!DOCTYPE html>
<html lang="en"><head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }
​
        #box {
            width: 600px;
            height: 600px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns:  1fr 1fr 1fr ;
            grid-template-rows:  1fr 1fr 1fr;
            grid-template-areas: "a b c"
                                 "d d d"
                                 "e f f";
        }
        .item {
            background-color: red;
            color: #fff;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 20px;
            box-sizing: border-box;
            padding: 20px;
            background-clip: content-box;
        }
​
        .item:nth-child(1) {
            grid-area: d;
        }
    </style>
</head><body>
    <div id="box">
        <div class="item">1</div>
    </div>
</body></html>

image.png

呜呼,是不是很快啊~哈哈

justify-content与align-content

justyfy管主轴,align管副轴。(我是这样记的,和flex一样的)

如果我们定义的网格没有布满整个盒子:

 #box {
            width: 600px;
            height: 600px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns:  100px 100px 100px ;
            grid-template-rows:  100px 100px 100px;
        }

image.png

这时我们想移动整个网格,就要使用justfy-content与align-content了。他的属性值有6个:我们都应该很熟悉,全是flex里面的...

  • start:网格与网格容器的左边/顶部对齐(默认)
  • end:网格与网格容器的右边/底部对齐
 #box {
          justify-content: end;
          align-content: end;
        }

image.png

  • center:网格与网格容器的中间对齐
 #box {
          justify-content: center;
          align-content: center;
        }

image.png

  • space-around:在 grid item 之间设置均等宽度/高度的空白间隙,其外边缘间隙大小为中间空白间隙宽度的一半
 #box {
          justify-content: space-around;
          align-content: space-around;
        }

image.png

  • space-between:在 grid item 之间设置均等宽度/高度空白间隙,其外边缘无间隙
 #box {
          justify-content: space-between;
          align-content: space-between;
        }

image.png

  • space-evenly:每个 grid item 之间设置均等宽度/高度的空白间隙,包括外边缘
 #box {
          justify-content: space-evenly;
          align-content: space-evenly;
        }

image.png

place-content属性 设置 align-content 和 justify-content 的简写

#box {
    place-content: <align-content> <justify-content>;
}

如果省略第二个值,则将第一个值同时分配给这两个属性

justfy-items与align-items

就是操作我们网格里面的所有的小盒子的。(content是操作整个网格,item是操作网格里的子盒子)他的属性有4个:

  • start:内容与网格区域的左端/顶端对齐(默认)
 #box {
            width: 300px;
            height: 300px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            grid-template-rows: repeat(3, 1fr);
        }
​
        .item {
            width: 50px;
            height: 50px;
            background-color: red;
            color: #fff;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 20px;
            box-sizing: border-box;
            padding: 2px;
            background-clip: content-box;
        }

image.png

  • end:内容内容与网格区域的右端/底部对齐
#box {
            width: 300px;
            height: 300px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns:  repeat(3,1fr) ;
            grid-template-rows:   repeat(3,1fr);
            justify-items:end;
            align-items:end;
        }

image.png

  • center:内容位于网格区域的中间/垂直中心位置
#box {
            width: 300px;
            height: 300px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns:  repeat(3,1fr) ;
            grid-template-rows:   repeat(3,1fr);
            justify-items:center;
            align-items:center;
        }

image.png

  • stretch:内容宽度/高度占据整个网格区域空间(当子盒子没有设置具体的宽高才起作用,且为默认)
#box {
            width: 300px;
            height: 300px;
            margin: 10px auto;
            border: 1px solid red;
            display: grid;
            grid-template-columns:  repeat(3,1fr) ;
            grid-template-rows:   repeat(3,1fr);
        }
        .item {
            background-color: red;
            color: #fff;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 20px;
            box-sizing: border-box;
            padding: 2px;
            background-clip: content-box;
        }

image.png

place-items属性 设置 align-items和 justify-items的简写

#box {
    place-items: <align-items> <justify-items>;
}

如果省略第二个值,则将第一个值同时分配给这两个属性

justify-self与align-self

沿着行/列轴对齐grid item 里的内容。此属性对单个网格项内的内容生效的。作用和justify-itemsalign-items一模一样。就是对象不一样了,justify-itemsalign-items是在网格容器盒子上面设置的,且对它的所有子盒子都有效;而justify-selfalign-self是在网格容器里的子盒子上面设置的,且只对自己有效。

它的属性值和justify-itemsalign-items也是一样的,start、end、center、stretch

它也有简写:

place-self属性

设置 align-selfjustify-self 的简写形式

#box {
    place-content: <align-self> <justify-self> | auto;
}

如果省略第二个值,则将第一个值同时分配给这两个属性

其实如果会flex布局的话,掌握这个grid布局真的很轻松唉!