Flex布局经验汇总

2021-07-22 fishedee 前端

0 概述

Flex布局,这个布局学了很久了,每次都是学了又忘,学了又忘,这次要决心把它学起来

Flex布局的关键知识点在于:

  • 父flex的,主轴方向,环绕,整体排列,辅轴方向的元素对齐,整体对齐
  • 子flex的,个体排序,宽度,剩余宽度伸展分配,超出宽度缩减分配,次轴方向的个体对齐

1 父flex

代码在这里

1.1 主轴方向,flex-direction

<style>
    .flex1{
        display: flex;
        flex-direction: row;
    }
    .flex2{
        display: flex;
        flex-direction: column;
    }
</style>
<div class="flexBox">
    <h1>flex-direction:row direction</h1>
    <div class="flex1">
        <div class="rent">a</div>
        <div class="rent">b</div>
        <div class="rent">c</div>
    </div>
    <h1>flex-direction:column direction</h1>
    <div class="flex2">
        <div class="rent">a</div>
        <div class="rent">b</div>
        <div class="rent">c</div>
    </div>
</div>

使用flex-direction来设置主轴方向,是横放,还是竖放。flex-direction还有个row-reverse和column-reverse,就是行列不变,只是元素反过来存放而已。

这个简单,没啥好说的

1.2 主轴环绕,flex-wrap

<style>
.flex3{
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
}
.flex4{
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
}
</style>
<div class="flexBox">
    <h1>flex-wrap:no wrap</h1>
    <div class="flex3">
        <div class="bigRent">a</div>
        <div class="bigRent">b</div>
        <div class="bigRent">c</div>
        <div class="bigRent">d</div>
        <div class="bigRent">e</div>
        <div class="bigRent">f</div>
        <div class="bigRent">g</div>
        <div class="bigRent">h</div>
        <div class="bigRent">i</div>
    </div>
    <h1>flex-wrap:wrap</h1>
    <div class="flex4">
        <div class="bigRent">a</div>
        <div class="bigRent">b</div>
        <div class="bigRent">c</div>
        <div class="bigRent">d</div>
        <div class="bigRent">e</div>
        <div class="bigRent">f</div>
        <div class="bigRent">g</div>
        <div class="bigRent">h</div>
        <div class="bigRent">i</div>
    </div>
</div>

默认的flex-wrap为no-wrap,就是不环绕

这个也简单

1.3 主轴间隙,gap

<style>
.flex21{
    display: flex;
    gap:10px;
    flex-wrap: wrap;
}
.flex22{
    display: flex;
    column-gap:20px;
    flex-wrap: wrap;
}
.flex23{
    display: flex;
    row-gap:30px;
    flex-wrap: wrap;
}
</style>
<div class="flexBox">
    <h1>flex-direction:gap 10</h1>
    <div class="flex21">
        <div class="rent">a</div>
        <div class="rent">b</div>
        <div class="rent">c</div>
        <div class="rent">a</div>
        <div class="rent">b</div>
        <div class="rent">c</div>
        <div class="rent">a</div>
        <div class="rent">b</div>
        <div class="rent">c</div>
    </div>
    <h1>flex-direction:column gap 20</h1>
    <div class="flex22">
        <div class="rent">a</div>
        <div class="rent">b</div>
        <div class="rent">c</div>
        <div class="rent">a</div>
        <div class="rent">b</div>
        <div class="rent">c</div>
        <div class="rent">a</div>
        <div class="rent">b</div>
        <div class="rent">c</div>
    </div>
    <h1>flex-direction:row gap 30</h1>
    <div class="flex23">
        <div class="rent">a</div>
        <div class="rent">b</div>
        <div class="rent">c</div>
        <div class="rent">a</div>
        <div class="rent">b</div>
        <div class="rent">c</div>
        <div class="rent">a</div>
        <div class="rent">b</div>
        <div class="rent">c</div>
    </div>
</div>

间隙描述的是主轴,以及环绕时候的间隙。默认的gap是0,同时表达了row-gap与column-gap。而column-gap是水平方向的间隙,row-gap是垂直方向的间隙

这点也是很直观的

注意,这个gap属性在IE下是不能正常运行的,需要在各个子控件中加入margin属性。如果你是用React的话,不妨改用Antd的Space控件来代替,它可以实现不同浏览器上的兼容性。

1.4 主轴排列,justify-content

<style>
.flex5{
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
}
.flex6{
    display: flex;
    flex-direction: row;
    justify-content: flex-end;
}
.flex7{
    display: flex;
    flex-direction: row;
    justify-content: center;
}
.flex8{
    display: flex;
    flex-direction: row;
    justify-content: space-between;
}
.flex9{
    display: flex;
    flex-direction: row;
    justify-content: space-around;
}
</style>
<div class="flexBox">
    <h1>justify-content:flex-start</h1>
    <div class="flex5">
        <div class="rent">a</div>
        <div class="rent">b</div>
        <div class="rent">c</div>
    </div>
    <h1>justify-content:flex-end</h1>
    <div class="flex6">
        <div class="rent">a</div>
        <div class="rent">b</div>
        <div class="rent">c</div>
    </div>
    <h1>justify-content:center</h1>
    <div class="flex7">
        <div class="rent">a</div>
        <div class="rent">b</div>
        <div class="rent">c</div>
    </div>
    <h1>justify-content:space-between</h1>
    <div class="flex8">
        <div class="rent">a</div>
        <div class="rent">b</div>
        <div class="rent">c</div>
    </div>
    <h1>justify-content:space-around</h1>
    <div class="flex9">
        <div class="rent">a</div>
        <div class="rent">b</div>
        <div class="rent">c</div>
    </div>
</div>

这里就开始有点混乱了,justify-content描述的是,在主轴方向,内容整体如何排列,包括:

  • 整体靠左(flex-start),默认值
  • 靠右(flex-end)
  • 中间(center)
  • 中间有空隙均匀排列(space-between)
  • 两侧有空隙均匀排列(space-around)

justify-content描述的是,主轴方向(justify),内容整体(content)如何排列

1.5 辅轴元素对齐,align-items

<style>
.flex10{
    display: flex;
    flex-direction: row;
    align-items: flex-start;
}
.flex11{
    display: flex;
    flex-direction: row;
    align-items: flex-end;
}
.flex12{
    display: flex;
    flex-direction: row;
    align-items: center;
}
.flex13{
    display: flex;
    flex-direction: row;
    align-items: baseline;
}
.flex14{
    display: flex;
    flex-direction: row;
    align-items: stretch;
}
.flexAlignItems .rent,
.flexAlignItems .rent2,
.flexAlignItems .rent3,
.flexAlignItems .rent4{
    height:auto;
}
</style>
<div class="flexBox flexAlignItems">
    <h1>align-items:flex-start</h1>
    <div class="flex10">
        <div class="rent">a</div>
        <div class="rent2">b</div>
        <div class="rent3">c</div>
        <div class="rent4">d</div>
    </div>
    <h1>align-items:flex-end</h1>
    <div class="flex11">
        <div class="rent">a</div>
        <div class="rent2">b</div>
        <div class="rent3">c</div>
        <div class="rent4">d</div>
    </div>
    <h1>align-items:center</h1>
    <div class="flex12">
        <div class="rent">a</div>
        <div class="rent2">b</div>
        <div class="rent3">c</div>
        <div class="rent4">d</div>
    </div>
    <h1>align-items:baseline</h1>
    <div class="flex13">
        <div class="rent">a</div>
        <div class="rent2">b</div>
        <div class="rent3">c</div>
        <div class="rent4">d</div>
    </div>
    <h1>align-items:stretch</h1>
    <div class="flex14">
        <div class="rent">a</div>
        <div class="rent2">b</div>
        <div class="rent3">c</div>
        <div class="rent4">d</div>
    </div>
</div>

当元素在主轴排列以后,它在副轴就就可以选择,元素之间在副轴的对齐,包括:

  • flex-start,元素的头部在副轴方向对齐
  • flex-end,元素的尾部在副轴方向对齐
  • center,元素的中间在副轴方向对齐
  • baseline,元素的基线在副轴方向对齐
  • stretch,元素在副轴方向拉伸对齐,仅当元素在副轴的没有设置大小时,默认值

align-items,描述的是在副轴方向(align),各个元素(items)之间拿什么进行对齐

1.6 辅轴整体对齐,align-content

<style>
.flex15{
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-content: flex-start;
    height:500px;
}
.flex16{
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-content: flex-end;
    height:500px;
}
.flex17{
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-content: center;
    height:500px;
}
.flex18{
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-content: stretch;
    height:500px;
}
.flex19{
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-content: space-between;
    height:500px;
}
.flex20{
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-content: space-around;
    height:500px;
}
</style>
<div class="flexBox">
    <h1>align-content:flex-start</h1>
    <div class="flex15">
        <div class="bigRent">a</div>
        <div class="bigRent">b</div>
        <div class="bigRent">c</div>
        <div class="bigRent">d</div>
        <div class="bigRent">e</div>
        <div class="bigRent">f</div>
        <div class="bigRent">g</div>
        <div class="bigRent">h</div>
        <div class="bigRent">i</div>
    </div>
    <h1>align-content:flex-end</h1>
    <div class="flex16">
        <div class="bigRent">a</div>
        <div class="bigRent">b</div>
        <div class="bigRent">c</div>
        <div class="bigRent">d</div>
        <div class="bigRent">e</div>
        <div class="bigRent">f</div>
        <div class="bigRent">g</div>
        <div class="bigRent">h</div>
        <div class="bigRent">i</div>
    </div>
    <h1>align-content:center</h1>
    <div class="flex17">
        <div class="bigRent">a</div>
        <div class="bigRent">b</div>
        <div class="bigRent">c</div>
        <div class="bigRent">d</div>
        <div class="bigRent">e</div>
        <div class="bigRent">f</div>
        <div class="bigRent">g</div>
        <div class="bigRent">h</div>
        <div class="bigRent">i</div>
    </div>
    <h1>align-content:stretch</h1>
    <div class="flex18">
        <div class="bigRent">a</div>
        <div class="bigRent">b</div>
        <div class="bigRent">c</div>
        <div class="bigRent">d</div>
        <div class="bigRent">e</div>
        <div class="bigRent">f</div>
        <div class="bigRent">g</div>
        <div class="bigRent">h</div>
        <div class="bigRent">i</div>
    </div>
    <h1>align-content:space-between</h1>
    <div class="flex19">
        <div class="bigRent">a</div>
        <div class="bigRent">b</div>
        <div class="bigRent">c</div>
        <div class="bigRent">d</div>
        <div class="bigRent">e</div>
        <div class="bigRent">f</div>
        <div class="bigRent">g</div>
        <div class="bigRent">h</div>
        <div class="bigRent">i</div>
    </div>
    <h1>align-content:space-around</h1>
    <div class="flex20">
        <div class="bigRent">a</div>
        <div class="bigRent">b</div>
        <div class="bigRent">c</div>
        <div class="bigRent">d</div>
        <div class="bigRent">e</div>
        <div class="bigRent">f</div>
        <div class="bigRent">g</div>
        <div class="bigRent">h</div>
        <div class="bigRent">i</div>
    </div>
</div>

副轴整体对齐,是指在副轴方向上,内容整体如何对齐,包括:

  • flex-start,内容整体在副轴方向的头部对齐
  • flex-end,内容整体在副轴方向的尾部对齐
  • center,内容整体在副轴方向的中央对齐
  • stretch,内容整体在副轴方向顺序wrap对齐
  • space-between,内容整体在副轴方向的中间有空隙均匀排列
  • space-around,内容整体在副轴方向的两侧有空隙均匀排列

align-content,描述的是在副轴方向(align)上,内容整体(content)如何对齐

1.7 父flex盒子,dispaly

<style>
.flex1{
    display:inline-flex;
}
.flex2{
    display:flex;
}
</style>

可以设置为inline或者block方式的flex,这点与block与inline-block的区别是一样的,就没啥好说的了

1.8 语法糖,flex-flow

<style>
.flex{
    flex-flow:row nowrap;
}
</style>

flex-flow就是flex-direction,与flex-wrap的组合而已,这点也没啥好说的

2 子flex

代码在这里

2.1 顺序,order

<style>
.flexBox{
    margin-top:30px;
    border-bottom:1px solid black;
}
.flex{
    display: flex;
    flex-direction: row;
    width:100%;
}
</style>
<div class="flexBox">
    <h1>order</h1>
    <div class="flex">
        <div class="rent" style="order:2">a</div>
        <div class="rent" style="order:1">b</div>
        <div class="rent" style="order:3">c</div>
    </div>
</div>

order也很好理解,就是强行指定渲染的顺序,而不是以DOM的出现来分主次

这个还是比较直观的

2.2 主轴大小,flex-basis

<div class="flexBox">
    <h1>flex-basis</h1>
    <div class="flex">
        <div class="rent" style="flex-basis:100px">a</div>
        <div class="rent" style="flex-basis:200px">b</div>
        <div class="rent" style="flex-basis:400px">c</div>
    </div>
</div>

flex-basis,可以用百分比,也可以用像素,它描述的是主轴方向的大小。在row方向的时候,我们也可以用width来描述节点的大小呀,为什么要用flex-basis。因为flex-basis的优先级更高。默认值为auto。总的来说,优先级等级为:

  • flex-basis,最高
  • width或者height,显式在css指定它的宽或者高
  • content width或者content height,内容自身的宽或者高

这点也没啥好说的,具体可以看这里

2.3 主轴剩余空间分配,flex-grow

<div class="flexBox">
    <h1>flex-grow</h1>
    <div class="flex">
        <div class="rent" style="flex-grow:0">a</div>
        <div class="rent" style="flex-grow:1">b</div>
        <div class="rent" style="flex-grow:2">c</div>
    </div>
</div>

当flex是row方向nowrap的时候,多个元素的大小总和依然少于父flex的宽度的时候,就会产生主轴的剩余空间分配。它的分配方法也简单,就是按照flex-grow的权重进行分配,默认的flex-grow为0,就是该元素不分配剩余空间。经过剩余空间分配以后,flex总是能保证元素的总宽度刚好为父flex的宽度

我们看到c的flex-grow为2,b的flex-grow为1,所以,c总是能比b多1倍的剩余宽度。

剩余宽度的计算公式看这里,要注意尽可能不要让权重总和少于1,会产生你意外的布局效果,会造成剩余宽度不分配的情况。

2.4 主轴缩减空间分配,flex-shrink

<style>
.rentLong{
    margin:15px;
    border:1px solid black;
    color:red;
    background: blue;
    width:500px;
    height:30px;
    text-align:center;
    line-height: 30px;
    vertical-align: middle;
}
</style>
<div class="flexBox">
    <h1>flex-shrink</h1>
    <div class="flex">
        <div class="rentLong" style="flex-shrink:1">a</div>
        <div class="rentLong" style="flex-shrink:2">b</div>
        <div class="rentLong" style="flex-shrink:4">c</div>
    </div>
</div>

每个子div的长度都是500像素,显然会超出父flex的总宽度。那么,各个子flex就需要承担等比例收缩宽度的任务,他们各自需要收缩多少,显然这也是flex-shrink的事情,他通过权重来做等比例的收缩。经过缩减空间分配以后,flex总是能保证元素的总宽度刚好为父flex的宽度

如图所示,虽然a,b,c都是500像素的宽度,但是c的flex-shrink权重最大,所以它被缩减的空间最大。

缩减宽度的计算公式看这里,要注意尽可能不要让权重总和少于1,会产生你意外的布局效果,会造成剩余宽度不分配的情况。另外,权重的计算不仅会考虑flex-shrink,也会考虑width自身,这是因为我们尽量避免原来大width的组件收缩的程度太大。如果对所有组件的flex-shrink设置为1,那么flex布局就会根据原来组件自身的width尽可能等比例的收缩。

2.5 副轴元素对齐,align-self

<div class="flexBox">
    <h1>align-self</h1>
    <div class="flex2">
        <div class="rent">a</div>
        <div class="rent">b</div>
        <div class="rent" style="align-self: flex-end;">c</div>
    </div>
</div>

align-self其实就是父flex的align-items的各自特别版本而已,这个也没啥好说的

align-self的可能取值与align-items的是一致的

2.6 语法糖,flex

<style>
    .flex{
        flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
    }
</style>

flex其实是flex-grow,flex-shrink与flex-basis的组合语法糖而已,默认可以省略flex-shrink与flex-basis,只写flex-grow也是没问题的。

3 应用

代码在这里

3.1 管理系统布局

<style>
*{
    margin:0px;
    padding:0px;
}
.flex{
    display: flex;
    flex-direction: column;
    align-items: stretch;
    width:100%;
    height: 100vh;
}
.flex .header{
    height:70px;
    background: blue;
}
.flex .flex2{
    flex:1;
    display: flex;
}
.flex .sidebar{
    width:70px;
    background: red;
}
.flex .content{
    flex:1;
    background: pink;
}
.flex .footer{
    height: 70px;
    background: yellow;
}
</style>
<div>
    <h1>flex admin</h1>
    <div class="flex">
        <div class="header">
            header
        </div>
        <div class="flex2">
            <div class="sidebar">
                sidebar
            </div>
            <div class="content">
                content
            </div>
        </div>
        <div class="footer">
            footer
        </div>
    </div>
</div>

注意一下用100vh来描述屏幕高度

3.2 等比例布局

<style>
*{
    margin:0px;
    padding:0px;
}
.flex{
    display: flex;
}
.flex div{
    flex-basis:25%;
    text-align: center;
    border:1px solid black;
}
</style>
<div>
    <h1>flex 25%precent</h1>
    <div class="flex">
        <div>a</div>
        <div>b</div>
        <div>c</div>
        <div>d</div>
    </div>
</div>

直接用flex-basis的百分比就可以了,注意,border的大小不影响flex-basis的布局,也不修改box-sizing属性,也不需要考虑空格问题,确实好用。

3.3 垂直与宽度居中

<style>
*{
    margin:0px;
    padding:0px;
}
.center1{
    display: flex;
    justify-content: center;
    align-items: center;
    height:300px;
    border:1px solid black;
}
</style>
<div>
    <h1> flex center</h1>
    <div class="center1">
        <p>123456</p>
    </div>
</div>

直接用justify-content和align-items就可以了,如果有多个item,就用justify-content和align-content。比原来的方法也好用多了。

3.4 类float布局

<style>
*{
    margin: 0px;
    padding: 0px;
}
.flex{
    border:1px solid blue;
    padding: 30px;
}
.flex .item{
    display: flex;
    width: 300px;
    border:1px solid black;
    align-items: flex-start;
}
.flex .item img{
    flex:0;
    width: 30px;
}
.flex .item p{
    flex:1;
}
</style>
<div>
    <h1>flex hang</h1>
    <div class="flex">
        <div class="item">
            <img src="./icon.jpg"/>
            <p>你好你好你好你好你好你好你好你好你好你好你好你好你好你好</p>
        </div>
        <div class="item">
            <img src="./icon.jpg"/>
            <p>你好你好你好你好你好你好你好你好你好你好你好你好你好你好</p>
        </div>
    </div>
</div>

一侧有图片,另外一侧占用剩余宽度,两者顶部对齐,也是简单的

3.5 左右浮动布局

<style>
*{
    margin:0px;
    padding:0px;
}
.right1{
    display: flex;
    flex-direction: row;
}
.right1 .l{
    flex:0;
}
.right1 .c{
    flex:1;
    text-align: center;
}
.right1 .r{
    flex: 0;
}
</style>
<div>
    <h1>flex right</h1>
    <div class="right1">
        <div class="l">left</div>
        <div class="c">center</div>
        <div class="r">right</div>
    </div>
</div>

左右浮动,可以看成是justify-content的space-between,也可以看成是主轴三部分,中间部分占据所有的剩余宽度。

4 总结

有用且兼容性较好的布局方式,需要转换一下思维,难度并不大。参考资料

相关文章