Web前端入门第 38 问:CSS flex 弹性盒子与 grid 网格布局区别及应用场景

弹性盒子又称为 Flexbox,然而我更喜欢 flex 的叫法。

flex 弹性盒子和 grid 网格布局作为前端开发中两把利器,它们的分界线没那么明显,虽然按照 MDN 的说法 flex 多用于一维布局(行/列),grid 多用于二维布局(行列网格),但实际开发中用多个一维布局也能拼凑出一个完整的二维布局。

grid 主要用来简化 html 结构,在一些二维布局的场景下,使用 flex 时需要更复杂的 html 结构支撑,而使用 grid 则可以尽可能的简化 html 结构。

我的理解 flex 擅长细节上的雕琢,而 grid 更擅长宏观上的调控。

flex 的应用场景

下面细说 flex 的应用场景,及同时使用 grid 会怎样实现。

网页导航

随处可见的网页导航布局,看图:

使用 flex 实现可以是这样的代码结构:

html 复制代码
<div class="nav">
  <div class="item">首页</div>
  <div class="item">新闻</div>
  <div class="item">产品</div>
  <div class="item">联系我们</div>
  <div class="item">公司简介</div>
  <div class="item">关于我们</div>
</div>
<style>
  .nav {  
    width: 100%;
    display: flex;
  }
  .nav .item {
    margin-right: 40px;
  }
</style>

使用 grid 实现的代码结构:

html 复制代码
<div class="nav">
  <div class="item">首页</div>
  <div class="item">新闻</div>
  <div class="item">产品</div>
  <div class="item">联系我们</div>
  <div class="item">公司简介</div>
  <div class="item">关于我们</div>
</div>
<style>
  .nav {  
    width: 100%;
    display: grid;
    grid-auto-flow: column; /* 按列排列 */
    grid-auto-columns: max-content; /* 新增列的宽度由内容决定 */
  }
  .nav .item {
    margin-right: 40px;
  }
</style>

可以看到,在处理一维布局时候,flex 可以说是得心应手,grid 则需要多写一些代码。

flex 的代码长得小清新一样,而 grid 总感觉有点长歪了~

常见的左右布局

再看这种常见的栏目标题布局:

使用 flex 实现:

html 复制代码
<div class="modules">
  <div class="title">
    <h3 class="name">栏目标题</h3>
    <a href="javascript" class="more">更多 ></a>
  </div>
  <code class="code">
  </code>
</div>
<style>
  .modules {  
    border: 2px solid rgba(255, 71, 87,0.3);
    border-radius: 8px;
    width: 300px;
    height: 300px;
  }
  .modules .title {
    padding: 0 12px;
    display: flex;
    justify-content: space-between; /* 左右两端对齐 */
    align-items: center; /* 上下垂直居中 */
  }
</style>

使用 grid 实现:

html 复制代码
<div class="modules">
  <div class="title">
    <h3 class="name">栏目标题</h3>
    <a href="javascript" class="more">更多 ></a>
  </div>
  <code class="code">
  </code>
</div>
<style>
  .modules {  
    border: 2px solid rgba(255, 71, 87,0.3);
    border-radius: 8px;
    width: 300px;
    height: 300px;
  }
  .modules .title {
    padding: 0 12px;
    display: grid;
    grid-auto-flow: column; /* 按列排列 */
    justify-content: space-between; /* 左右两端对齐 */
    align-items: center; /* 上下垂直居中 */
  }
</style>

对比下来,使用 grid 的代码还是多了一行 grid-auto-flow: column;,小清新的 flex 还是要苗条一点~

常见的左左右布局

以百度首页的热搜导航为例:

使用 flex 实现:

以下示例代码巧用了 margin-left: auto; 让元素跑到右侧位置。

html 复制代码
<div class="nav">
  <div class="item">我的关注</div>
  <div class="item">百度热搜</div>
  <div class="change">换一换</div>
</div>
<style>
  .nav {
    width: 650px;
    display: flex;
  }
  .nav .item {
    margin-right: 24px;
  }
  .nav .change {
    margin-left: auto; /* 巧用 auto */
  }
</style>

使用 grid 实现:

html 复制代码
<div class="nav">
  <div class="item">我的关注</div>
  <div class="item">百度热搜</div>
  <div class="change">换一换</div>
</div>
<style>
  .nav {
    width: 650px;
    display: grid;
    grid-template-columns: max-content max-content 1fr; /* 三列网格,最后一列占用剩余空间 */
  }
  .nav .item {
    margin-right: 24px;
  }
  .nav .change {
    justify-self: flex-end;
  }
</style>

对比下来,还是 flex 布局更显得小清新一点。

一维布局 flex 与 grid 对比

对比了几种常见的一维列布局,使用 flex 比使用 grid 代码要简洁一点,虽然都能达到想要的效果,当然是代码越少越好了。

gird 应用场景

看完了一维布局的几个应用场景,再看看 grid 的应用场景。

经典的网页分区

页面的整体框架结构无外乎那几种,我们看一种最常见的管理平台的页面分区:

使用 grid 实现:

html 复制代码
<div class="layout">
  <div class="header">Header</div>
  <div class="aside">Aside</div>
  <div class="main">Main</div>
  <div class="footer">Footer</div>
</div>
<style>
  .layout {
    width: 900px;
    height: 270px;
    display: grid;
    grid-template-areas: 
      "aside header"
      "aside main"
      "aside footer";
    grid-template-columns: 200px 1fr;
    grid-template-rows: 60px 1fr 60px;
  }
  .header {
    grid-area: header;
    background-color: rgb(198, 226, 255);
  }
  .aside {
    grid-area: aside;
    background-color: rgb(217, 236, 255);
  }
  .main {
    grid-area: main;
    background-color: rgb(236, 245, 255);
  }
  .footer {
    grid-area: footer;
    background-color: rgb(198, 226, 255);
  }
</style>

使用 flex 实现:

html 复制代码
<div class="layout">
  <div class="header">Header</div>
  <div class="right-container">
    <div class="aside">Aside</div>
    <div class="main">Main</div>
    <div class="footer">Footer</div>
  </div>
</div>
<style>
  .layout {
    width: 900px;
    height: 270px;
    display: flex;
  }
  .header {
    flex: 0 0 200px;
    background-color: rgb(198, 226, 255);
  }
  .right-container {
    flex: 1;
    display: flex;
    flex-direction: column;
  }
  .aside {
    flex: 0 0 60px;
    background-color: rgb(217, 236, 255);
  }
  .main {
    flex: 1;
    background-color: rgb(236, 245, 255);
  }
  .footer {
    flex: 0 0 60px;
    background-color: rgb(198, 226, 255);
  }
</style>

可以看到虽然 flex 也实现了一样的页面分区效果,但 HTML 的结构确要比 grid 更加复杂,需要嵌套更多的 HTML 结构用来实现复杂的二维布局。

卡片列表

看一种最常见的卡片列表布局:

使用 grid 实现:

html 复制代码
<div class="list">
  <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>
<style>
  .list {
    width: 600px;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
  }
  .item {
    height: 200px;
    background-color: rgba(255, 71, 87,0.3);
  }
</style>

使用 flex 实现:

html 复制代码
<div class="list">
  <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>
<style>
  .list {
    width: 600px;
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
  }
  .item {
    flex: 0 0 193px; /* 这儿必须明确指定宽度 (600px - 10px * 2) / 3 = 193px */
    height: 200px;
    background-color: rgba(255, 71, 87,0.3);
  }
</style>

flex 实现的卡片列表必须明确指定一个宽度,这个宽度值需要减去列间距得出;而 grid 实现的这种卡片列表则无需考虑这种计算问题,直接会自动适应。

二维布局 flex 与 grid 对比

在二维布局领域,grid 当之无愧的强大,虽然 flex 也可以实现一毛一样的效果,当不可避免的是代码冗余。

总结

flex 在一维布局中更能发挥优势,grid 在宏观布局或二维布局中优势更加明显。

在不考虑代码冗余的情况下,flex 和 grid 都能在对方领域抢饭碗。

实际开发中,grid 标准浏览器都是在 2017 年之后才实现的,flex 标准则是在 2012 年就开始支持,项目但凡需要兼容老古董浏览器,grid就别想了,赖克宝吃不到小天鹅~~