Flex 布局语法及实例

    Flex元素是可以让你的布局根据浏览器的大小变化进行自动伸缩。

    Flexbox布局(Flexible Box)模块旨在提供一个更加有效的方式制定、调整和分布一个容器里的项目布局,即使他们的大小是未知或者是动态的。(这里我们称为Flex)。

    Flex布局主要思想是让容器有能力让其子项目能够改变其宽度、高度(甚至顺序),以最佳方式填充可用空间(主要是为了适应所有类型的显示设备和屏幕大小)。Flex容器会使子项目(伸缩项目)扩展来填满可用空间,或缩小他们以防止溢出容器。

    布局的传统解决方案,基于盒状模型,依赖 display属性 + position属性 + float属性。它对于那些特殊布局非常不方便,比如,垂直居中就不容易实现。-ruanyifeng


    基本概念

    flex示意图

    1. 伸缩容器:一个设有“display:flex”或“display:inline-flex”的元素
    2. 伸缩项目:伸缩容器的子元素
    3. 容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。
    4. 主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;
    5. 交叉轴的开始位置叫做cross start,结束位置叫做cross end。
    6. 项目默认沿主轴排列。单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size。

    先煮个栗子


    首先要给父容器添加display:flex或者inline-flex属性。再利用flex-grow给项目添加比例。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    .parent-box{
    display: -webkit-flex;
    display: flex;
    width:400px;
    height: 100px;
    color:white;
    font-size: 25px;
    border:1px solid #333;
    }

    1
    2
    3
    4
    5
    6
    7
    8
    .box1{
    flex-grow:1;
    background: #8E0FAF;
    }
    .box2{
    flex-grow:2;
    background: #F7E892;
    }

    下面就是简单的DOM结构

    1
    2
    3
    4
    5
    <div class="parent-box">
    <div class="box1"></div>
    <div class="box2"></div>
    <div class="box1"></div>
    </div>

    那么此时整个宽度为400px的容器,就被分成了3个部分。并且比例为1:2:1。此时紫色的区域为100px,黄色区域为200px。注意,设为Flex布局以后,子元素的float、clear和vertical-align属性将失效。下面的例子部分基于此例。


    容器具有的属性

    • flex-direction 属性决定主轴的方向(即项目的排列方向)
    • flex-wrap 属性定义,如果一条轴线排不下,如何换行。
    • flex-flow 属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap
    • justify-content 属性定义了项目在主轴上的对齐方式。
    • align-items 属性定义项目在交叉轴上如何对齐。
    • align-content 属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。

    详细解释如下:

    flex-direction属性决定主轴的方向(即项目的排列方向)

    1
    flex-direction: row | row-reverse | column | column-reverse;

    分别给parent-box添加这些样式将会得到下面的情形:
    flex-direction

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    .parent-box1{
    flex-direction:column;//横向排列,主轴为水平方向,起点在左端。
    }
    .parent-box2{
    flex-direction:row;//纵向排列,轴为垂直方向,起点在上沿。
    }
    .parent-box3{
    flex-direction:row-reverse;//纵向排列,主轴为水平方向,起点在右端。
    }
    .parent-box4{
    flex-direction:column-reverse;//横向排列并且相反,主轴为水平方向,起点在右端。
    }

    注意这里是基于上面的一个例子,利用类样式分离(把公共的代码提取出来)可以减少代码。这里在parent-box的样式上,增加了上面的parent-box1。其余的几个类似。

    1
    2
    3
    4
    5
    <div class="parent-box parent-box1">
    <div class="box1">1</div>
    <div class="box2">2</div>
    <div class="box1">3</div>
    </div>


    flex-wrap属性定义,如果一条轴线排不下,如何换行

    1
    flex-wrap: nowrap | wrap | wrap-reverse;
    1. nowrap(默认):不换行。
    2. wrap:换行,第一行在上方。
    3. wrap-reverse:换行,第一行在下方。

    比如我一个盒子设置为了400px,我一共有三个子盒子,并且一个盒子是150px,那么400px肯定是放不下这三个盒子的。此时利用flex-wrap可以解决此时是换行还是不换行的问题。如果设置为不换行,那么此时这400px会再次等分。相当于刚刚设置的每个盒子150px失效。如果设置为换行,那么此时将会分成上下两行。为了看得更清楚我给父容器设置了边框。效果如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    .parent-box5{
    -webkit-flex-wrap:wrap;
    flex-wrap:wrap;
    }
    .parent-box6{
    -webkit-flex-wrap:nowrap;
    flex-wrap:nowrap;
    }
    .parent-box7{
    -webkit-flex-wrap:wrap-reverse;
    flex-wrap:wrap-reverse;
    }

    注意换成两行后,第二行是不占据空间的。这个怎么办,。。求解?

    1
    2
    3
    4
    5
    <div class="parent-box parent-box5">
    <div class="box3">3</div>
    <div class="box4">4</div>
    <div class="box5">5</div>
    </div>


    flex-flow是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap

    1
    flex-flow: <flex-direction> || <flex-wrap>;

    justify-content属性定义了项目在主轴上的对齐方式

    可以取下面5个值

    1
    justify-content: flex-start | flex-end | center | space-between | space-around;


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    .parent-box8{
    justify-content:flex-start;
    }
    .parent-box9{
    justify-content:flex-end;
    }
    .parent-box10{
    justify-content:center;
    }
    .parent-box11{
    justify-content:space-between;
    }
    .parent-box12{
    justify-content:space-around;
    }


    align-items属性定义项目在交叉轴上如何对齐

    1
    align-items: flex-start | flex-end | center | baseline | stretch;


    align-content属性定义了多根轴线的对齐方式

    如果项目只有一根轴线,该属性不起作用。

    1
    align-content: flex-start | flex-end | center | space-between | space-around | stretch;


    上面讲的都是容器的属性,其实还有项目的属性。

    • orderorder属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。
    • flex-grow此属性值为正数值,用来设置扩展比率,也就是剩余空间是正值的时候此伸缩项目相对于伸缩容器里其他伸缩项目能分配到空间比例。若省略则会被设置为“1”。
    • flex-shrink此属性值为正数值,用来设置收缩比率,也就是剩余空间是负值的时候此伸缩项目相对于伸缩容器里其他伸缩项目能收缩的空间比例。若省略则会被设置为“1”,在收缩的时候收缩比率会以伸缩基准值加权。
    • flex-basisflex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
    • flexflex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
    • align-selfalign-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。

    举几个flex的例子

    flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
    例子1——flex-grow与flex-basis

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #first {
    flex: 1 200px;
    }
    #second {
    flex: 2 300px;
    }
    #third {
    flex: 1 250px;
    }

    首先flex-basis的值主要取决于伸缩项目的width或者高,同时取决于流动方向。然后,剩下的空间根据flex-grow给伸缩项目最后宽度来划分。所以伸缩项目会沿着主轴线大小为200px、300px和250px,总共750px。如果伸缩容器沿主轴方向是950px,这样就会多出一个200px空间,那么这多出的200px空间将分配给伸缩项目。第一个和第三个伸缩项目将得到50px的空间,因为他的flex-grow值是“1”,他们最终的空间是250px和300px。第二个伸缩项目将获得100px空间,因为他的flex-grow值为“2”,他的最后空间大小为400px。

    例子2——flex-grow与flex-shrink与flex-basis

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #first {
    flex: 1 1 400px;
    }
    #second {
    flex: 2 3 600px;
    }
    #third {
    flex: 1 2 400px;
    }

    flex-shrink称为收缩比率。这个值只有伸缩项目在没主轴方向溢出伸缩容器才会发挥作用。他们充当比例值,但这回指的是溢出量,将这个溢出量按比例分配给每个伸缩项目,用于防止伸缩容器溢出。

    比如说,我们伸缩容器沿主轴方向宽度是1100px,按照上面的示例代码计算,我们的伸缩项目会超出300px(伸缩项目沿主轴方向总值为1400px),这个时候通过flex-shrink收缩他们:

    • 第一个伸缩项目将得到溢出量的六分之一,也就是50px,这个时候他的值为350px(在当初的基础上减少50px)。
    • 第二个伸缩项目将得到溢出量的六分之三,也就是150px,这个时候他的值为450px(在当初的基础上减少150px)。
    • 第三个伸缩项目将得到溢出的六分之二,就就是100px,这个时候他的值为300px(在当初的基础 上减少100px)。

    这样flex-shrink使用伸缩项目得到一个较小的宽度。

    例子3——align-self属性可以实现的效果
    align-self图片from ryf


    旧版本的box flex

    这个以前有写旧的写法(只列举了部分),详细可以看:旧写法(通过审查元素即可看) 其语法不同,而且也更加不兼容。比如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #parent-box{
    display: -moz-box;
    display: -webkit-box;
    display: box;
    .....
    }
    #parent-box2{
    -moz-box-orient:horizontal|vertical;
    -webkit-box-orient:horizontal|vertical;
    box-orient:horizontal|vertical;
    }
    #box1{
    -moz-box-flex:1;
    -webkit-box-flex:1;
    box-flex:1;
    }


    大概知道Flex是干什么的了。感谢阮一峰的文章,这个绝对讲的清楚。