CSS Grid 布局

308 阅读7分钟

我们提供了以下 HTML 与 CSS 布局:

<!DOCTYPE html>
<html>

<head>
  <title>Using CSS Grid</title>
  <style>
    body {
      color: #fff;
      font-family: 'Nunito Semibold';
      text-align: center;
    }

    #content {
      max-width: 960px;
      margin: 0 auto;
    }

    #content div {
      background: #3bbced;
      padding: 30px;
    }

    #content div:nth-child(even) {
      background: #777;
      padding: 30px;
    }
  </style>
</head>

<body>

  <div id="content">

    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
    <div>6</div>
    <div>7</div>
    <div>8</div>
    <div>9</div>

  </div>

</body>

</html>

运行效果如下

image-20230909112420945.png

下面我们将进行 grid 布局的尝试

columns 列

grid-template-columns 通过设置每列占的比例进行布局。这里值里面写了几个,那么就有几列,各列按照比例选择宽度。

通过百分比布局

设置为三列,每列比例相同

#content {
	display: grid; /* 首先说明这个大盒子为 grid 布局 */
    grid-template-columns: 33.3% 33.3% 33.3%; /* 三列,每列比例相同 */
    max-width: 960px;
  	margin: 0 auto;
}

效果如下:

image-20230909112929826.png

设置为三列,每列所占比例为 30% 20% 50%

#content {
	display: grid; /* 首先说明这个大盒子为 grid 布局 */
    grid-template-columns: 30% 20% 50%; /* 三列,每列所占比例为 30% 20% 50% */
    max-width: 960px;
  	margin: 0 auto;
}

效果如下:

image-20230909113141255.png

通过分数(fraction)布局

设置为三列,每列比例 1 : 2 : 1

#content {
	display: grid; /* 首先说明这个大盒子为 grid 布局 */
    grid-template-columns: 1fr 2fr 1fr; /* 三列,每列所占比例 1 : 2 : 1 */
    max-width: 960px;
  	margin: 0 auto;
}

效果如下

image-20230909113358916.png

设置为三列,每列比例相同

#content {
	display: grid; /* 首先说明这个大盒子为 grid 布局 */
    grid-template-columns: repeat(3, 1fr); /* 三列,每列所占比例相同 */
    max-width: 960px;
  	margin: 0 auto;
}

效果如下

image-20230909113554031.png

rows 行

假设 #content 如下

#content {
	display: grid; /* 首先说明这个大盒子为 grid 布局 */
    grid-template-columns: repeat(3, 1fr); /* 三列,每列所占比例相同 */
    max-width: 960px;
  	margin: 0 auto;
}

我们将第三个 <div> 内容修改为

<div>Lorem ipsum dolor sit amet consectetur adipisicing elit. Nulla maiores quod eum consequuntur voluptate ad
consequatur nostrum, repellat minus consectetur laborum totam tempora temporibus, dolores expedita commodi
veritatis quos laudantium?
</div>

效果如下:

image-20230909162212250.png

第一行的三个盒子因为第三个盒子内容过多被自动撑开了。

下面通过设置 row 行 来对每行高度进行设置:

设置盒子最小高度 100px,最大高度设置为 auto(随着文字增多变高)

 #content {
      display: grid;/* 首先说明这个大盒子为 grid 布局 */
      grid-template-columns: repeat(3, 1fr); /* 三列,每列所占比例相同 */
      grid-auto-rows: minmax(100px, auto); /* 高度最低100px,最高auto */
      max-width: 960px;
      margin: 0 auto;
    }

效果如下:

image-20230909162809265.png

设置每行高度相同,都为第三个盒子撑大的高度

#content {
  display: grid;/* 首先说明这个大盒子为 grid 布局 */
  grid-template-columns: repeat(3, 1fr); /* 三列,每行所占比例相同 */
  grid-template-rows: repeat(3, 1fr);  /* 三行,每行所占比例相同 */
  max-width: 960px;
  margin: 0 auto;
}

效果如下:

image-20230909163115527.png

如果改为:

content {
  display: grid;/* 首先说明这个大盒子为 grid 布局 */
  grid-template-columns: repeat(2, 1fr); /* 三列,每行所占比例相同 */
  grid-template-rows: repeat(2, 1fr);
  max-width: 960px;
  margin: 0 auto;
}

效果如下:

image-20230909163228808.png

改为:

content {
  display: grid;/* 首先说明这个大盒子为 grid 布局 */
  grid-template-columns: repeat(3, 1fr); /* 三列,每行所占比例相同 */
  grid-template-rows: repeat(4, 1fr);
  max-width: 960px;
  margin: 0 auto;
}

效果如下:

image-20230909163336386.png

发现多了一行,虽然这里没有盒子,但还是会占用空间(创建了网格)

gap 间隙

假设 #content 是这样:

#content {
  display: grid;/* 首先说明这个大盒子为 grid 布局 */
  grid-template-columns: repeat(3, 1fr); /* 三列,每行所占比例相同 */
  grid-template-rows: repeat(3, 1fr);
  max-width: 960px;
  margin: 0 auto;
}

效果:

image-20230909163115527.png

我们来设置每行每列的间隙

先设置每列的间隙:

#content {
  display: grid;/* 首先说明这个大盒子为 grid 布局 */
  grid-template-columns: repeat(3, 1fr); /* 三列,每行所占比例相同 */
  grid-template-rows: repeat(3, 1fr);
  grid-column-gap: 20px;
  max-width: 960px;
  margin: 0 auto;
}

效果如下:

image-20230909163903916.png

每行也设置:

#content {
    display: grid;/* 首先说明这个大盒子为 grid 布局 */
    grid-template-columns: repeat(3, 1fr); /* 三列,每行所占比例相同 */
    grid-template-rows: repeat(3, 1fr);
    max-width: 960px;
    grid-column-gap: 20px;
    grid-row-gap: 20px;
    margin: 0 auto;
}

效果如下:

image-20230909164113543.png

我们来检查一下,发现盒子并没有添加 margin

image-20230909164200584.png(单个盒子检查)

原来是盒子之间添加了间隙,但间隙不是这些小盒子的属性,是这个网格布局的属性

image-20230909164302760.png

column & row lines

现在更新一下 <div id="content"> 中的内容为 6 个盒子,且每个盒子都加了class

<div id="content">
    <div class="one">1</div>
    <div class="two">2</div>
    <div class="three">3</div>
    <div class="four">4</div>
    <div class="five">5</div>
    <div class="six">6</div>
</div>

#content 为:

#content{
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    grid-template-rows: repeat(4, minmax(150px, auto));
    grid-gap: 10px;  /* 注意:也支持这样设置间隙 */
    max-width: 960px;
    margin: 0 auto;
}

也就是我们有 6 个盒子,画了一个 (6+1)*(4+1) 的网格。

效果如下:

image-20230909171526850.png

下面我们开始布局

对第一个盒子设置:

.one {
  grid-column-start: 1;
  grid-column-end: 3;
  /* 或者 grid-column: 1 / 3; */
}

效果如下:

image-20230909171806886.png

还可以设置 row

.one {
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}

效果如下:

image-20230909171929164.png

其他的盒子设置方法相同

nested grids 网格布局里面套一个网格布局

假设我们有#content大盒子下面的 6 个盒子

<div id="content">
    <div>1</div>
    <div>2</div>
    <div>3</div>

    <div class="nested">
        <p>1</p>
        <p>2</p>
        <p>3</p>
        <p>4</p>
    </div>

    <div>5</div>
    <div>6</div>

其中 #content

#content{
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-gap: 10px;
    max-width: 960px;
    margin: 0 auto;
}

在第四个盒子我们给他设置 grid 布局:

.nested{
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-gap: 10px;
    /*grid-column: span 3;*/
}
.nested p{
    border: 1px solid #fff;
    padding: 20px;
    margin: 0;
}

效果如图:

image-20230909190933283.png

aligning & justifying items 设置盒子的位置

align-jtems & justify-items 默认是 stretch 拉伸属性

给出盒子:

<div id="content">
    <div class="one">1 with content</div>
    <div class="two">2</div>
    <div class="three">3</div>
    <div class="four">4</div>
    <div class="five">5</div>
    <div class="six">6</div>
</div>

#content 样式:

#content{
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-auto-rows: minmax(150px, auto);
    grid-gap: 10px;
    max-width: 960px;
    margin: 0 auto;
}

效果如下:

image-20230909193529655.png

由于这两个属性默认是 stretch,所以盒子会铺满整个划分出来的网格,我们可以通过手动设置不让盒子铺满网格,还能设置盒子出现的位置。

align-items#content盒子中的所有盒子出现在网格垂直方向的上、中、下位置

出现在上位置(start)、中位置(center)、下位置(end)

下面以上位置举例

#content{
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-auto-rows: minmax(150px, auto);
    grid-gap: 10px;
    max-width: 960px;
    margin: 0 auto;
    align-items: start;
}

效果如下:

image-20230909194119656.png

可以看到,这些小盒子目前在垂直方向不再是 stretch 拉伸状态了,然而在水平位置还是 stretch 状态

justify-items#content 盒子中所有盒子出现在网格水平方向左、中、右位置

出现在左位置(start)、中位置(center)、右位置(end)

下面以中位置举例:

我们使用已经设置了 align-items: start 开始:

#content{
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-auto-rows: minmax(150px, auto);
    grid-gap: 10px;
    max-width: 960px;
    margin: 0 auto;
    align-items: start;
    justify-items: center;
}

效果如下:

image-20230909194722804.png

盒子出现在了水平方向上的中位置

align-self & justify-self 设置单个盒子(自己)的位置

假设 #content 样式:

#content{
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-auto-rows: minmax(150px, auto);
    grid-gap: 10px;
    max-width: 960px;
    margin: 0 auto;
}

效果如下:

image-20230909195216896.png

是默认的 stretch 拉伸样式。

我们来试试设置第一个盒子位置,设置为左下位置:

.one {
  align-self: end;
  justify-self: start;
}

效果如下:

image-20230909195159485.png

实例测试 Example: create a 12-column grid

使用 grid 进行简单的布局,并且还设置了一个点击按钮显示出辅助线的功能:

<!DOCTYPE html>
<html>
<head>
<title>Using CSS Grid</title>
<style>
    body{
        color: #fff;
        font-family: 'Nunito Semibold';
        text-align: center;
    }
    #content{
        display: grid;
        grid-template-columns: repeat(12, 1fr);
        grid-auto-rows: minmax(100px, auto);
        grid-gap: 10px;
        max-width: 960px;
        margin: 0 auto;
        position:relative;
    }
    #content > *{
        background: #3bbced;
        padding: 30px;
    }
    header{
        grid-column: 1 / 13;
    }
    main{
        grid-column: 4 / 13;
        grid-row: 2 / 4;
    }
    aside{
        grid-column: 1 / 4;
    }
    nav{
        grid-column: 1 / 4;
    }
    section{
        grid-column: 1 / 13;
        grid-row: 4 / 6;
    }
    footer{
        grid-column: 1 / 13;
    }

    #grid{
        position: absolute;
        top: 0;
        left: 0;
        display: grid;
        grid-template-columns: repeat(12, 1fr);
        grid-auto-rows: minmax(100%, auto);
        width: 100%;
        height: 100%;
        background: transparent;
        padding: 0;
        display: none;
    }
    input:checked + #content #grid{
        display: grid;
    }
    #grid p{
        border: 1px solid;
        background: #000;
        margin: 0;
        opacity: 0.2;
    }
</style>
</head>
<body>

<input type="checkbox" />
<div id="content">

    <div id="grid">
        <p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p>
    </div>

    <header>Header</header>
    <main>Main</main>
    <section>Section</section>
    <aside>Aside</aside>
    <nav>Nav</nav>
    <footer>Footer</footer>

</div>

</body>
</html>

效果如下:

unchecked:

image-20230909202829556.png

checked:

image-20230909202844773.png

grid areas

可以通过这个功能快速构建出网页布局框架

给出如下 HTML 结构:

<body>

<div id="content">

    <header>Header</header>
    <main>Main</main>
    <section>Section</section>
    <aside>Aside</aside>
    <nav>Nav</nav>
    <footer>Footer</footer>

</div>

</body>

CSS 样式

body{
    color: #fff;
    font-family: 'Nunito Semibold';
    text-align: center;
}
#content{
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-auto-rows: minmax(100px, auto);
    grid-gap: 10px;
    max-width: 960px;
    margin: 0 auto;
}
#content > *{
    background: #3bbced;
    padding: 30px;
}

效果如下:

image-20230909210811017.png

给每个盒子取一个 area 名字,然后通过简单的字符串组合布局( . 表示该网格中没盒子)

#content{
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-auto-rows: minmax(100px, auto);
    grid-gap: 10px;
    max-width: 960px;
    margin: 0 auto;
    grid-template-areas:
        "header header header header"
        "aside . main main"
        "nav . main main"
        "section section section section"
        "section section section section"
        "footer footer footer footer";
}
header{
    grid-area: header;
}
main{
    grid-area: main;
}
aside{
    grid-area: aside;
}
nav{
    grid-area: nav;
}
section{
    grid-area: section;
}
footer{
    grid-area: footer;
}

效果如下:

image-20230909212854868.png

references 参考文献