通俗示例讲解——flex实现等比布局

2,541 阅读3分钟

flex布局的基本概念可以看一下阮一峰的文章www.ruanyifeng.com/blog/2015/0… 相信写过flex布局的同学基本都看过。这篇文章着重探究在实际开发中遇到的flex-grow,flex-shrink,flex-basic

一. 示例代码

  1. 实现1:1:1:1 布局
<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>flex布局</title>
</head>
<style>
.parent {
    display: flex;
    width: 800px;
    height: 200px;
    background-color: bisque;
}
.child1 {
    flex: 1 1 0%;  
    background-color: cadetblue;
    height: 100px;
}
.child2 {
    flex: 1 1 0%;  
    background-color: coral;
    height: 100px;
}
.child3 {
    flex: 1 1 0%;  
    background-color: darkgreen;
    height: 100px;
}
.child4 {
    flex: 1 1 0%;  
    background-color: darkred;
    height: 100px;
}
</style>
<body>
    <div class="parent">
        <div class="child1">child1</div>
        <div class="child2">child2</div>
        <div class="child3">child3</div>
        <div class="child4">child4</div>
    </div>
</body>
</html>

截屏2021-09-23 下午3.49.13.png

  1. 实现一个1:2:3:4等比布局?
.child1 {
    flex: 1 1 0%;  
    background-color: cadetblue;
    height: 100px;
}
.child2 {
    flex: 2 1 0%;  
    background-color: coral;
    height: 100px;
}
.child3 {
    flex: 3 1 0%;  
    background-color: darkgreen;
    height: 100px;
}
.child4 {
    flex: 4 1 0%;  
    background-color: darkred;
    height: 100px;
}

截屏2021-09-23 下午3.56.11.png

  1. 实现 20px : 1 : 3 : 100px 布局
.child1 {
    flex: 0 0 20px;  
    background-color: cadetblue;
    height: 100px;
    word-break: break-all;  // 不然子元素会超出去
}
.child2 {
    flex: 1 1 0%;  
    background-color: coral;
    height: 100px;
}
.child3 {
    flex: 3 1 0%;  
    background-color: darkgreen;
    height: 100px;
}
.child4 {
    flex: 0 0 100px;  
    background-color: darkred;
    height: 100px;
}

截屏2021-09-23 下午4.02.19.png

🌟踩坑 子元素中的内容溢出,会导致宽度不符合预期,所以需要注意一下。

.child1 {
    flex: 0 0 20px;  
    background-color: cadetblue;
    height: 100px;
    /* word-break: break-all; */ 注释掉
}

截屏2021-09-23 下午5.49.22.png

二. 原理

如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

所以,设置flex-basic: 0%,这个属性值会让父级主轴在计算剩余空间时忽略子元素的本身宽度,从而实现等比分配。

三. 宽度验证练习 公式:

剩余宽度: 父元素宽度 - 父元素两边的padding - flex-basis之和(有时候padding也算,具体情况具体分析) 
平均一份剩余宽度: 剩余宽度 / (flexgrow之和)
子元素宽度:flex-basis + 按比例均摊到的剩余宽度 + (就不加上padding,具体情况具体分析)
  1. 如果parent是border-box,给父元素设置padding,会影响剩余长度。
<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>flex布局</title>
</head>
<style>
.parent {
    display: flex;
    padding: 0px 100px;
    box-sizing: border-box;
    width: 800px;
    height: 200px;
    background-color: bisque;
}
.child1 {
    flex: 0 0 50px;  
    background-color: cadetblue;
    height: 100px;
}
.child2 {
    flex: 1 1 0%;  
    background-color: coral;
    height: 100px;
}
.child3 {
    flex: 3 1 0%;  
    background-color: darkgreen;
    height: 100px;
}
.child4 {
    flex: 0 0 100px;  
    background-color: darkred;
    height: 100px;
}
</style>
<body>
    <div class="parent">
        <div class="child1">child1 50px</div>
        <div class="child2">child2 112.5px</div>
        <div class="child3">child3 337.5px</div>
        <div class="child4">child4 100px</div>
    </div>
</body>
</html>

截屏2021-09-23 下午6.03.44.png

计算步骤:

800px - (100px + 100px) - (50px + 100px) = 450px
450px / (1 + 3) = 112.5px
child2:0% * 800px + 112.5px * 1 = 112.5px
child: 0% * 800px + 112.5px * 3 = 337.5px


        
  1. 给子模块设置padding/margin,会在最终生成子元素宽度之后,加上padding。举例:
<!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>flex布局</title>
</head>
<style>
.parent {
    display: flex;
    padding: 0px 100px;
    box-sizing: border-box;
    width: 800px;
    height: 200px;
    background-color: bisque;
}
.child1 {
    flex: 0 0 50px;  
    background-color: cadetblue;
    height: 100px;
}
.child2 {
    flex: 1 1 0%;  
    background-color: coral;
    height: 100px;
    padding-right: 20px;
}
.child3 {
    flex: 3 1 0%;  
    background-color: darkgreen;
    height: 100px;
    padding-right: 30px;
}
.child4 {
    flex: 0 0 100px;  
    background-color: darkred;
    height: 100px;
}
</style>
<body>
    <div class="parent">
        <div class="child1">child1 50px</div>
        <div class="child2">child2 100px + 20px</div>
        <div class="child3">child3 300px + 30px</div>
        <div class="child4">child4 100px</div>
    </div>
</body>
</html>

截屏2021-09-23 下午6.10.19.png

计算步骤:

800px - (100px + 100px) - (50px + 100px + 20px + 30px) = 400px
400px / (1 + 3) = 100px
child2:0% * 800px + 100px * 1 + 20px = 120px
child: 0% * 800px + 1oopx * 3 + 30px = 330px
        

结论:

  1. 想要严格实现等比布局,flex-basic: 0%;

  2. 如果parent是border-box,给父元素设置padding,会影响剩余长度。

  3. 给子模块设置padding/margin, ①子模块box-sizing:boredr-box, 这个时候padding是作为宽度的一部分存在的,所以取max(padding, basic)作为主轴上的基础宽度。计算剩余宽度的时候要减掉这个basic。最终这个子元素的宽度就是 flex-basis + 按比例均摊到的剩余宽度 ②子模块box-sizing:content-box,这个时候padding是作为flex-basic之后,额外占位的一个宽度,所以计算剩余宽度的时候,要减去padding与flex-basic之和。最终这个子元素的宽度就是flex-basis + 按比例均摊到的剩余宽度 + padding

四. 补充:涉及到padding的例子

  1. child2 设置padding: 20px box-sizing: content-box;
<!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>flex布局</title>
</head>
<style>
.parent {
    display: flex;
    width: 800px;
    height: 200px;
    background-color: bisque;
}
.child1 {
    flex: 0 0 50px;  
    background-color: cadetblue;
    height: 100px;
}
.child2 {
    flex: 1 1 10%;  
    background-color: coral;
    /* box-sizing: border-box; */
    height: 100px;
    padding-right: 20px;
}
.child3 {
    box-sizing: border-box;
    flex: 3 1 20%;  
    background-color: darkgreen;
    height: 100px;
}
.child4 {
    flex: 0 0 100px;  
    background-color: darkred;
    height: 100px;
}
</style>
<body>
    <div class="parent">
        <div class="child1">child1 50px</div>
        <div class="child2">child2 177.5px + 20px</div>
        <div class="child3">child3 452.5px</div>
        <div class="child4">child4 100px</div>
    </div>
</body>
</html>

截屏2021-09-23 下午8.15.18.png

计算步骤:

800px - (50px + 100px + 800px * 10% + 20px + 800px * 20%) = 390px
390px / (1 + 3) = 97.5px
child2:800px * 10% + 97.5px * 1 + 20px = 177.5px + 20px
child: 800px * 20% + 97.5 * 3 = 452.5px
  1. child2 设置padding: 20px box-sizing: border-box;
<!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>flex布局</title>
</head>
<style>
.parent {
    display: flex;
    width: 800px;
    height: 200px;
    background-color: bisque;
}
.child1 {
    flex: 0 0 50px;  
    background-color: cadetblue;
    height: 100px;
}
.child2 {
    flex: 1 1 10%;  
    background-color: coral;
    box-sizing: border-box;   // !!!!
    height: 100px;
    padding-right: 20px;
}
.child3 {
    box-sizing: border-box;
    flex: 3 1 20%;  
    background-color: darkgreen;
    height: 100px;
}
.child4 {
    flex: 0 0 100px;  
    background-color: darkred;
    height: 100px;
}
</style>
<body>
    <div class="parent">
        <div class="child1">child1 50px</div>
        <div class="child2">child2 177.5px + 20px</div>
        <div class="child3">child3 452.5px</div>
        <div class="child4">child4 100px</div>
    </div>
</body>
</html>

截屏2021-09-23 下午8.22.53.png

计算步骤:
realbasic = max(800px * 10%, 20) = 80px
800px - (50px + 100px + realbasic + 800px * 20%) = 410px
410px / (1 + 3) = 102.5px
child2:realbasic + 102.5px * 1 = 182.5px
child: 800px * 20% + 102.5 * 3 = 467.5px