Skip to content

网格布局 ​

强烈推荐阅读CSS Grid 网格布局教程 还有 MDN Grid 布局相关文档

https://www.bilibili.com/video/BV134411m7dJ

介绍 ​

grid 布局是一种新的, 强大的 css 布局方式, 与 flex 有很多相似的地方, 都是在一个容器中, 设置多个子项的属性(如:宽度, 位置) 但是 flex(弹性布局) 是根据 主轴侧轴 来实现布局的, 但是 grid 则是 将容器分为 行 和 列 来管理 子项的, 行和列都可以有多个, 说起来和表格也有相似之处, 但是却比表格更强大, 但是兼容性没有表格好

grid

兼容性 ​

使用 caniuse 查看 grid 兼容性

容器和子项 ​

和 flex 类似, 只要将显示模式修改为 grid 就可以获得一个 grid 布局的容器

只要是 grid 容器中的元素都可以算做 grid 的子项

html
<div class="grid-box">
  <div class="item"></div>
  <div class="item"></div>
</div>
css
.grid-box {
  display: grid;
  /* display: inline-grid; */
}

网格线和单元格 ​

定义网格容器 ​

css
.grid-box {
  display: grid; /* 或者, display:inline-grid */
}

划分容器行和列 ​

和 flex 布局不同的是, flex 布局是按照轴线来设置尺寸和对齐方式, 但是 grid 布局可以像表格那样划分 行(row) 和 列(column), 子项可以按照 划分的行列来设置尺寸和对齐方式

基本使用 ​

  • grid-template-columns
  • grid-template-rows
css
/* 不仅仅只是可以使用 px 也可以使用 rem vw 等其他具体单位 */
.grid-box {
  width: 300px;
  height: 300px;
  display: grid;
  grid-template-rows: 100px 100px 100px;
  grid-template-columns: 100px 100px 100px; /* 3行3列的九宫格 */
}
css
/* 按照容器元素根据比例缩放 */
.grid-box {
  width: 600px;
  height: 600px;
  display: grid;
  grid-template-rows: 33.33% 33.33% 33.33%;
  grid-template-columns: 33.33% 33.33% 33.33%; /* 3行3列的九宫格 */
}

repeat 和 minmax 函数 ​

css
/*
如果css属性的多个取值是一样的, 全部手写太麻烦了, 还容易出错
可以使用 repeat 函数来简写
*/
.grid-box {
  width: 600px;
  height: 600px;
  display: grid;
  grid-template-columns: repeat(10, 1fr); /* 10行10列的网格 */
  grid-template-rows: repeat(10, 1fr); /* 这种写法等同于: 1fr 1fr 1fr */
}
css
.grid-box {
  display: grid;
  grid-template-columns: minmax(200px, 400px) 1fr 1fr;
  /*
    1.网格容器没有设置宽度, 那么默认宽度会继承父元素的宽度
      如果要查看效果, 最好写到 body 里面, 然后手动缩放浏览器窗口

    2.将网格分为 3 列:
      第一列: 最小值为 200px, 最大值为 400px, 如果需要让最大值随容器缩放
              也可以使用 fr 单位: minmax(200px, 1fr) 这样设置
      第二列: 随网格容器的宽度缩放
      第三列: 随网格容器的宽度缩放
  */
}
css
.grid-box {
  display: grid;
  grid-template-columns: minmax(200px, 400px) repeat(4, 1fr);
  /*
    将容器分为 5 列:
    第一列: 最小为200px, 最大为 400px
    后面四列: 随着容器宽度缩放(容器总宽度 - 第一列宽度)平分 4 份
    其实可读性也非常好, 等价于:
    grid-template-columns: minmax(200px, 400px) 1fr 1fr 1fr 1fr;
  */
}

使用 fr 单位 ​

css
/*
在CSS中,"fr"代表"分数"(fraction)单位
它用于定义网格布局容器中的列或行的大小,以实现响应式设计
"fr"单位的工作原理是将可用空间分为等份,并根据每个项目的分配比例来确定其大小

grid-template-rows: 1fr 1fr 1fr; 将容器分为 3 份, 每行占 1 份
grid-template-rows: 1fr 3fr 1fr; 将容器分为 5 份, 第1,3行各占1份,第二行占3份
*/
.grid-box {
  width: 600px;
  height: 600px;
  display: grid;
  grid-template-rows: repeat(3, 1fr);
  grid-template-columns: repeat(3, 1fr);
}
css
.grid-box {
  display: grid;
  grid-template-columns: 100px 2fr 1fr;
  /* grid-template-columns: 100px auto 100px; */
}
/*
1. grid-template-columns: 100px 2fr 1fr;
  将容器分为 3 列:
    第一列: 宽度为 100px, 不随着容器缩放
    第二列: 宽度为 2 份, 随着容器宽度缩放
    第三列: 宽度为 1 份, 随着容器宽度缩放


2. grid-template-columns: 100px auto 100px;
  将容器分为 3 列:
    第一列: 宽度为 100px, 不随着容器宽度缩放
    第二列: 宽度为容器总宽度 - 200px(其实就是:1fr)
    第三列: 宽度为 100px, 不随着容器宽度缩放

注意: 只有所有列都使用可缩放单位(如: 33%, 1fr)时候, 才会使用容器总宽度来计算
*/

自动填充 ​

这个例子是自动填充行, 其实列也是可以自动填充的

css
/*
在实际开发中可能会遇到这样的需求:
不确定有多少条数据(没法提前知道有多少行和列, 但是可以设置容器的宽度)
但是可以一直下拉刷新更多的数据(知道子项的宽度和高度, 因为不管有多少条, 样式是不变的)
那么就可以使用自动填充, 让容器尽可能多的放下更多的子项
如以下的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>
*/
.container {
  background-color: #ccc;
  display: grid;
  width: 600px;
  grid-template-columns: repeat(auto-fill, 100px);
}

.item {
  height: 100px;
  background: #f00;
}

.item {
  width: 100px;
  height: 100px;
  background: #f00;
}
css
.container {
  background-color: #ccc;
  display: grid;
  width: 500px;
  grid-template-columns: repeat(auto-fill, 110px);
  /*
    每列 110px, 只能放 4 列(110 * 4), 因为 5 列就放不下了,
    每行多出 60 会直接留白, 可以将每列设置为 100px, 这样可以正好放下
    grid-template-columns: repeat(auto-fill, 100px);
  */
}

.item {
  height: 100px;
  background: #f00;
}

/**
  auto-fill 自动填充划分单元格是(例子为列,行也可以这样操作):
  每行自动填充列数 = 容器总宽度 / 每份的宽度 ( 500 / 110 = 4.5454 )
  如果无法(容器总宽度 / 每份的宽度)无法整除,
  并且使用的是不可缩放的单位(如上面那个例子) 那么会有多余的留白区域,
  所以: 要使用这种自动填充的, 建议使用可缩放的单位或者计算好宽度
**/

设置排列顺序 ​

默认的放置顺序是"先行后列", 即先填满第一行, 再开始放入第二行

  • grid-auto-flow

假设将网格分为3行3列的九宫格,并且有9各div

html
<div class="container">
  <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>
css
.container {
  display: grid;
  width: 300px;
  height: 300px;
  grid-gap: 10px;
  background: #ccc;
  grid-template-rows: repeat(3, 1fr);
  grid-template-columns: repeat(3, 1fr);
  /* grid-auto-flow: row; */
  /* 默认值: 先行后列, 元素排列顺序:
    1 2 3
    4 5 6
    7 8 9
  */
}

.item {
  background-color: #f00;
}
css
.container {
  display: grid;
  width: 300px;
  height: 300px;
  grid-gap: 10px;
  background: #ccc;
  grid-template-rows: repeat(3, 1fr);
  grid-template-columns: repeat(3, 1fr);
  grid-auto-flow: column;
  /* 先列后行, 元素排列顺序:
    1 4 7
    2 5 8
    3 6 9
  */
}

.item {
  background-color: #f00;
}

设置间距 ​

  • grid-row-gap
  • grid-column-gap
  • grid-gap: 这个属性是 grid-row-gap 和 grid-column-gap 的连写方式
css
.grid-box {
  /* grid-row-gap: 10px; */      /* 只设置行间距 */
  /* grid-column-gap: 10px; */   /* 只设置列间距*/
  /* grid-gap: 10px 10px; */     /* 分别设置行间距和列间距 */
  grid-gap: 10px;                /* 同时设置行间距和列间距 */
}

栅格命名 ​

栅格命名是为了后面更好的操作子项

css
.container {
  display: grid;
  width: 300px;
  height: 300px;
  grid-gap: 10px;
  background: #ccc;
  /* 命名用 [名称1 名称2], 如果要手动命名, 尽量用有意义的单词来描述, 并且最好是有规律 */
  grid-template-rows: [r1-start] 1fr [r1-end r2-start] 1fr [r2-end r3-start] 1fr [r3-end];
  grid-template-columns: [c1-start] 1fr [c1-end c2-start] 1fr [c2-end c3-start] 1fr [c3-end];
}
css
.container {
  display: grid;
  width: 300px;
  height: 300px;
  grid-gap: 10px;
  background: #ccc;
  grid-template-rows: repeat(3, [r-start] 100px [r-end]);
  /* 可以这样理解: [r-start 1] 1fr [r-end 1 r-start 2] 1fr [r-end 2 r-start 3] 1fr [r-start 3] */
  grid-template-columns: repeat(3, [c-start] 100px [c-end]);
  /* 可以这样理解: [c-start 1] 1fr [c-end 1 c-start 2] 1fr [c-end 2 c-start 3] 1fr [c-start 3] */
}
css
.container {
  display: grid;
  width: 300px;
  height: 300px;
  grid-gap: 10px;
  background: #ccc;
  grid-template-rows: 1fr 1fr 1fr;
  grid-template-columns: 1fr 1fr 1fr;
  /* 默认用数字命名, 可以这样理解: [1] 1fr [2] 1fr [3] 1fr [4] */
}

container

元素定位 ​

什么是元素定位?

可以将容器看作是一个带着格子的设计图, 那些线就是栅格(网格), 而子项就是要摆放的东西, 至于这个子项放到哪个位置, 占多高, 占多宽就不是容器来管了, 应该设置子项的属性, 如图

样式属性说明
grid-row-start行开始栅格线
grid-row-end行结束栅格线
grid-column-start列开始栅格线
grid-column-end列结束栅格线
grid-rowgrid-row-start/grid-row-end 的简写形式
grid-columngrid-column-start/grid-column-end 的简写形式
grid-areagrid-row-start/grid-column-start/grid-row-end/grid-column-end 的简写形式

注: 圈定的栅格区域必须是矩形(长方形/正方形)

注: grid-area 值的顺序必须按照规定的顺序来设置值

css
/* 手动命名 */
.item {
  background-color: #f00;
  grid-row-start: r2-start;
  grid-row-end: r2-end;
  grid-column-start: c2-start;
  grid-column-end: c2-end;
}
css
.container {
  display: grid;
  width: 300px;
  height: 300px;
  grid-gap: 10px;
  background: #ccc;
  grid-template-rows: [r1-start] 1fr [r1-end r2-start] 1fr [r2-end r3-start] 1fr [r3-end];
  grid-template-columns: [c1-start] 1fr [c1-end c2-start] 1fr [c2-end c3-start] 1fr [c3-end];
}
html
<div class="container">
  <div class="item">1</div>
</div>
css
/* 自动命名 */
.item {
  background-color: #f00;
  grid-row-start: r2-start;
  grid-row-end: r3-end;
  grid-column-start: c2-start;
  grid-column-end: c3-end;
}
css
.container {
  display: grid;
  width: 300px;
  height: 300px;
  grid-gap: 10px;
  background: #ccc;
  grid-template-rows: repeat(3, [row-start] 1fr [row-end]);
  grid-template-columns: repeat(3, [col-start] 1fr [col-end]);
  grid-auto-flow: column;
}
html
<div class="container">
  <div class="item">1</div>
</div>
css
/* 默认命名 */
.item {
  background-color: #f00;
  grid-row-start: 2;
  grid-row-end: 3;
  grid-column-start: 2;
  grid-column-end: 3;
}
css
.container {
  display: grid;
  width: 300px;
  height: 300px;
  grid-gap: 10px;
  background: #ccc;
  grid-template-rows: repeat(3, 1fr);
  grid-template-columns: repeat(3, 1fr);
}
html
<div class="container">
  <div class="item">1</div>
</div>
css
/* grid-row + grid-column 简写形式: 3种命名都可以使用简写方式 */
.item {
  background-color: #f00;
  grid-row: row-start 2 / row-end 2;
  grid-column: col-start 2 / col-end 2;
}
css
.container {
  display: grid;
  width: 300px;
  height: 300px;
  grid-gap: 10px;
  background: #ccc;
  grid-template-rows: repeat(3, [row-start] 1fr [row-end]);
  grid-template-columns: repeat(3, [col-start] 1fr [col-end]);
}
html
<div class="container">
  <div class="item">1</div>
</div>
css
/* grid-area 简写形式: 3种命名都可以使用简写方式 */
.item {
  background-color: #f00;
  grid-area: row-start 2 / col-start 2 / row-end 2 / col-end 2;
}
css
.container {
  display: grid;
  width: 300px;
  height: 300px;
  grid-gap: 10px;
  background: #ccc;
  grid-template-rows: repeat(3, [row-start] 1fr [row-end]);
  grid-template-columns: repeat(3, [col-start] 1fr [col-end]);
}
html
<div class="container">
  <div class="item">1</div>
</div>

使用区域布局 ​

在写后台的时候, 可能经常会写这样的布局, 其实用 grid 布局就可以很轻松的做到这样的布局

  • grid-template-areas: 定义模板
  • grid-area: 使用模板

分开定义模板 ​

css
html,
body {
  margin: 0;
  padding: 0;
}

.full-container {
  width: 100vw;
  height: 100vh;
  display: grid;
  grid-template-rows: 100px 1fr 50px;
  grid-template-columns: 300px 1fr;
  grid-template-areas:
    "header header"
    "aside main"
    "aside footer";
  /* 注意事项:
     使用模板布局时: 关键字的数量和grid-template-rows 和
     grid-template-columns 一定要相对应, 比如这个代码中
     的布局是 3 行(100px 1fr 50px) 2 列(300px 1fr)的布局
     那么关键字也必须是3行2列的布局:
     'area1 area1'
     'area2 area3'
     'area2 area4'
  */
}

.header {
  background: #f00;
  grid-area: header;
}

.aside {
  background: #0f0;
  grid-area: aside;
}

.main {
  background: #00f;
  grid-area: main;
}

.footer {
  background: #ff0;
  grid-area: footer;
}
html
<!doctype html>
<html lang="zh-cn">
  <head>
    <title>JavaScript</title>
    <link rel="stylesheet" type="text/css" href="./styles.css" />
  </head>
  <body>
    <div id="app" class="full-container">
      <header class="header">header</header>
      <aside class="aside">aside</aside>
      <main class="main">main</main>
      <footer class="footer">footer</footer>
    </div>
  </body>
</html>

简写定义模板 ​

上面代码效果图如下:

preview

对齐 ​

与 flex 类似, 在 grid 中也可以很方便的使用一些关键字来对其容器/子项

选项说明设置对象
justify-content所有栅格在容器中的水平对齐方式,容器有额外空间时容器
align-content所有栅格在容器中的垂直对齐方式,容器有额外空间时容器
align-items栅格内所有元素的垂直排列方式容器
justify-items栅格内所有元素的横向排列方式容器
align-self元素在栅格中垂直对齐方式子项
justify-self元素在栅格中水平对齐方式子项

取值范围:

值说明
start容器左边(水平方向) 容器上边(垂直方向)
end容器右边(水平方向) 容器下边(垂直方向)
center容器中间
stretch撑满容器
space-between均匀分布空间
space-around每个元素两侧的间隔相等
space-evenly栅格间距离完全平均分配

自动排列 ​

当栅格无法放置内容时, 系统会自动添加栅格用于放置溢出的元素, 我们需要使用以下属性控制自动添加栅格的尺寸

  • grid-auto-rows: 自动添加行的高度
  • grid-auto-columns: 自动添加列的宽度
css
ul,
li {
  margin: 0;
  padding: 0;
  list-style-type: none;
}

.list {
  width: 300px;
  height: 300px;
  display: grid;
  background: #f00;
  gap: 5px;
  grid-template-rows: 100px 100px;
  grid-template-columns: 100px 100px;
  grid-auto-columns: 200px; /* 宽度最大只能是 grid-template-columns 定义的中宽度 */
  grid-auto-rows: 200px; /* 高度可以撑开为 200 */
  /* 高度可以撑开, 但是宽度最大无法超过 grid-template-columns 定义的总宽度 */
}

.item {
  background: #0f0;
}
html
<ul class="list">
  <li class="item">item-1</li>
  <li class="item">item-2</li>
  <li class="item">item-3</li>
  <li class="item">item-4</li>
  <li class="item">item-5</li>
  <li class="item">item-6</li>
  <li class="item">item-7</li>
  <li class="item">item-8</li>
  <li class="item">item-9</li>
  <li class="item">item-10</li>
</ul>

效果图如下:

Released under the MIT License.