【css】从一个例子看 float,flex,grid 的优劣势

773 阅读2分钟

作者:李嘉豪 lijiahao043@ke.com

本文想用一个页面布局为例,横向对比一下 float,flex 和 grid 的优劣。

假如 UI 给了你一个原型图,让你实现如下布局。

image.png

float 方案

实现思路

首先,我们用最老的 float 方案试一试。我们的思路如下:

  • 首先 2 和 3 往左浮动,并给它们加一个 bfc 的 container;
  • 接着,给,2,3,1 加一个 container 并为之添加浮动,这个 container 与 4 的浮动同级。
  • 最后,需要给 2,3,1,4 加一个大的 bfc。5 正常排列即可。

代码

那么我们用代码实现一下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .container {
            font-size: 12px;
        }

        .container1 {
            overflow: hidden;
        }

        .container2 {
            float: left;
        }

        .box {
            width: 100px;
            height: 100px;
            margin: 5px;
            background-color: orange;
            float: left;
            font-size: 4em;
            text-align: center;
            line-height: 100px;
        }

        .box1 {
            width: 210px;
            height: 210px;
            float: none;
            line-height: 210px;
        }

        .box5 {
            float: none;
            width: 320px;
            height: 100px;

        }

        .box4 {
            width: 100px;
            height: 320px;
            line-height: 320px;
        }

        .bfc {
            overflow: hidden;
        }
    </style>
</head>

<body>
    <!-- 用 float 可以实现与 grid 相同的效果,但实现难度大且不如 grid 清晰,同时需要了解 bfc 相关的知识 -->
    <div class="container">
        <div class="bfc">
            <div class="container2">
                <!-- 需要用 bfc 清除浮动 -->
                <div class="bfc">
                    <div class="box box2">2</div>
                    <div class="box box3">3</div>
                </div>

                <div class="box box1">1</div>
            </div>
            <div class="box box4">4</div>
        </div>
        <div class="box box5">5</div>
    </div>
</body>

</html>

可以看到,使用 float 有一个比较大的弊端,就是为了清除浮动,你需要频繁的增加 bfc container,所以 html 代码写下来,到处都是 div 容器,不是很清晰。并且,使用 float 需要要求使用者对 bfc 的知识理解的比较清晰。

flex 方案

flex 的实现和 float 非常相似,区别是,由于 flex 的直接子元素自带 bfc,所以你不需要额外的添加 bfc 容器解决外边距重叠问题,也不需要清除浮动。

实现思路

  • 2 和 3 装到一个 flex container 里面
  • 2 和 3 的 container 和 1 放到一个 container 里,记为 c1
  • c1 和 4 放到一个 flex container 里面
  • 5 正常排

代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .container{
            font-size: 12px;
        }
        .box {
            background-color: orange;
            margin: 5px;
            font-size: 4em;
            text-align: center;
            line-height: 100px;
        }

        .flex {
            display: flex;
        }

        .box2,
        .box3 {
            width: 100px;
            height: 100px;
        }

        .box1 {
            width: 210px;
            height: 210px;
            line-height: 210px;
        }

        .box4 {
            width: 100px;
            height: 320px;
            line-height: 320px;
        }

        .box5 {
            width: 320px;
            height: 100px;
        }
    </style>
</head>

<body>
    <div class="container">
        <!-- flex 的直接下级元素会创建 bfc -->
        <div class="flex">
            <div>
                <div class="flex">
                    <div class="box box2">2</div>
                    <div class="box box3">3</div>
                </div>
                <div class="box box1">1</div>
            </div>
            <div class="box box4">4</div>
        </div>
        <div class="box box5">5</div>
    </div>
</body>

</html>

grid 方案

用 grid 方式实现的代码要比前两者整齐的多

实现思路

  • 5 个盒子直接顺序放到一个容器里
  • 容器使用 grid,分别用 grid-template-rows 和 grid-template-columns 指定行和列,用 grid-gap 指定元素间缝隙。
  • 子元素分别用 grid-row 和 grid-column 指定行和列从哪条网格线到哪条网格线

代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .container {
            /* 使用 grid 布局 */
            display: grid;
            /* 3 列 4 行 */
            grid-template-columns: repeat(3, 100px);
            grid-template-rows: repeat(4, 100px);
            /* 内部元素的缝隙 */
            grid-gap: 10px;
            font-size: 12px;
        }

        .box {
            background-color: orange;
            font-size: 4em;
            text-align: center;
            line-height: 100px;
        }

        .box1 {
            grid-row: 2/4;
            /*表示从第二个网格开始,从第四个网格结束*/
            grid-column: 1/3;
            line-height: 200px; /* text-align 使得文字水平居中,line-height 与 height 一致让文字垂直居中 */
        }

        .box4 {
            grid-row: 1/4;
            grid-column: 3/4;
            line-height: 300px;
        }

        .box5 {
            grid-row: 4/5;
            grid-column: 1/4;
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="box1 box">1</div>
        <div class="box2 box">2</div>
        <div class="box3 box">3</div>
        <div class="box4 box">4</div>
        <div class="box5 box">5</div>
    </div>
</body>

</html>

三者比较来看,似乎 grid 完胜,但其实 grid 也有自身的问题,那就是它的兼容性做的并不好,尤其是 h5。我们引用 segment fault 论坛中一位老哥的评价

image.png

但如果您能确定的是,使用你页面的人全部为 pc web 用户并且他们使用的浏览器版本比较新,你可以方向大胆的用 grid。grid 就是为了干这个事的。(解决复杂布局)

参考资料

【1】mdn developer.mozilla.org/zh-CN/docs/…

【2】阮一峰 www.ruanyifeng.com/blog/2019/0…

【3】segment fault segmentfault.com/q/101000000…

【4】我的代码 github.com/Ethan199412…