记Flex布局

828 阅读7分钟

前言

由于之前一直在开发b端的项目,基本都基于现有的组件库开发,手动写样式布局的情况很少,最近手里拿到了一个移动端的项目,正好进行下查缺补漏,希望也能对大家有一些小小滴帮助~

flex

flex也就是我们常说的Flexible Box("弹性"布局),我对"弹性"的理解是定义为display:flex为容器内的元素在"弹性"空间内可一放大或者缩小,flexbox是一种一维的布局,它提供了十分强大的空间分布和对齐能力,但是只能处理一行或者一列的一个纬度上的元素布局,任何一个容器都可以指定为flex布局,行内用display:inline-flex

设定为flex后,子元素的float、clear和vertical-align属性将失效。

弹性容器的属性

  • flex-direction

flex布局一共有两根轴线-主轴(main axis)和交叉轴(cross axis)。主轴就由flex-direction属性定义,另一根轴垂直与它,由于我们是一维布局,所以所有的flex属性都和这两根轴线有关,flex-direction有四个取值:

.item {
	flex-direction: "row" | "row-reverse" | "column" | "column-reverse";
}

定义为前两种主轴则横向伸展,后两种则纵向伸展。

  • flex-wrap

在默认的情况下,弹性盒子内元素在一条线上,默认不换行,flex-wrap属性定义了如果一排拍不下怎么换行,有三个取值:

.item {
	flex-wrap:"nowrap" | "wrap" | "wrap-reverse";
}

分别为不换行、向下换行、向上换行。

  • flex-flow

是上两种属性的简写:

.item {
	flex-flow: "flex-direction" | "flex-wrap";
}

默认为 row nowrap

  • justify-content | align-items | align-content

这三种属性定义分别定义了弹性盒子内元素在主轴和交叉轴,以及多根轴线时的对齐方式,我们可以借由这前两种属性实现简单的元素水平垂直居中:

.item {
    display:flex;
    justify-content:center;
    align-items: center;
}

justify-content有五种属性:

.item {
	justify-content: "flex-start" | "flex-end" | "center" | "space-between" | "space-around";
}

按顺序为左对齐、右对齐、居中、两端对齐,元素间距相等、每个项目间的距离都相等,所以两侧的距离才会看起来小于中间的。

align-items有五种属性:

.item {
	algin-items: "stretch" | "flex-start" | "flex-end" | "center" | "baseline";
}

按顺序为占满设置容器的高度、交叉轴的起点对齐、交叉轴的终点对齐、交叉轴的中点对齐、第一行的文字底部对齐。

algin-content定义了多跟轴线的对齐方式,只有一根轴线时不起作用,有六种属性:

.item {
	algin-content: "stretch" | "flex-start" | "flex-end" | "center" | "space-between" | "space-around";
}

按顺序为轴线占满整个交叉轴、交叉轴的起点对齐、交叉轴的终点对齐、交叉轴的中点对齐、两端对齐中间距离平分、两根轴线距离平分,所以两侧看起来小于中间的。

弹性元素的属性

  • order

弹性容器内的元素根据order去决定顺序,值是整数,值越小越靠前,默认为0.

.item {
	order: "整数";
}

  • flex-grow | flex-shrink | flex-basis

在说着三个属性之前我先说两个概念:正自由空间positive free space(个人理解:剩下的空间),负自由空间negative free space(个人理解:超出的空间)。

以这两张图片为例,500px的弹性容器,上边空余的200px就是剩下的,下边多出的100px就是超出的。

为什么要介绍这两个概念呢?

flex子元素没有positive free space 就不会增长, 没有negative free space 就不会缩小.也就是说我们所有元素的宽度加起来小于容器总宽,那么我们的flex-grow才会生效,反之我们所有元素的宽度加起来大于容器总宽,那么我们的flex-shrink才会生效。

flex-grow

该属性定义了flex元素在容器内的放大比例,默认为0,即不放大。

.item {
	flex-grow: "number";
}

如果我们定义了元素的flex-grow属性,且弹性容器有剩余的空间,我们的元素会根据flex-grow去分配剩余的空间,那我们是怎么计算该属性的呢,我写了下边的demo:

html部分:

<div class="container">
        <div class="one">A<br>width:100px<br>flex-grow:1</div>
        <div class="two">B<br>width:200px<br>flex-grow:2</div>
        <div class="three">C<br>width:150px<br>flex-grow:3</div>
</div>

css部分:

 * {
        margin: 0;
        padding: 0;
    }
    .container {
        width: 600px;
        height: 300px;
        display: flex;
        border: 2px dotted #333333;
        margin: 0 auto;
    }
    .container > div {
        text-align: center;
    }
    .one {
        width: 100px;
        flex-grow: 1;
        background-color: #ff4466;
    }
    .two {
        width: 200px;
        flex-grow: 2;
        background-color: #42b989;
    }
    .three {
        width: 150px;
        flex-grow: 3;
        background: #61daff;
    }

效果:

我们有如下的计算方式: 以A为例子,A的实际宽度为 width + A/(A+B+C)* X ,ABC分别为三个元素的flex-grow的值,X为剩余空间的大小,width为之前的宽度,依次计算下ABC的实际宽度为:125px250px225px.大家也可以自己尝试一下。

flex-shrink

该属性定义了元素的缩小比例,默认为1,则如果有溢出空间,将缩小。

.item {
	flex-shrink: "number";
}

如果我们定义了元素的flex-shrink属性,且弹性容器有超出的空间,我们的元素会根据flex-shrink去缩小,我们也通过下面我写的demo去看一下:

html部分:

<div class="container">
        <div class="one">A<br>width:300px<br>flex-shrink:1</div>
        <div class="two">B<br>width:300px<br>flex-shrink:2</div>
        <div class="three">C<br>width:300px<br>flex-shrink:3</div>
</div>

css部分:

    * {
        margin: 0;
        padding: 0;
    }
    .container {
        width: 600px;
        height: 300px;
        display: flex;
        border: 2px dotted #333333;
        margin: 0 auto;
    }
    .container > div {
        text-align: center;
    }
    .one {
        width: 300px;
        flex-shrink: 1;
        background-color: #ff4466;
    }
    .two {
        width: 300px;
        flex-shrink: 2;
        background-color: #42b989;
    }
    .three {
        width: 300px;
        flex-shrink: 3;
        background: #61daff;
    }

效果:

我们计算方式如下:还是以A为例子,首先计算压缩的权重,也就是系数,ABCflex-shrink的值,权重:weight = A * w1 + B * w2 + C * w3,X为多余的空间,则A的实际宽度就为300-(300/1800)*300 = 250px,也就是原有的宽度减去,压缩率乘多余的空间,压缩率的计算以A为例子就是A * w1 / weight.剩余的计算下来就是200px150px,大家也可以自己算一下。

flex-basis

该属性定义了在分配多余空间之前,元素占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的原本大小。

.item {
	flex-basis: "length" | "auto";
}

该属性和元素的宽度相关,我们通过一个demo看一下他和width min/max-width的优先级:

html部分:

<div class="container">
        <div class="box one">A</div>
        <div class="box two">B</div>
        <div class="box three">C</div>
</div>

css部分:

   * {
        margin: 0;
        padding: 0;
    }
    .container {
        width: 600px;
        height: 300px;
        display: flex;
        border: 2px dotted #333333;
        margin: 0 auto;
    }
    .box {
        text-align: center;
    }
    .one {
        width: 100px;
        flex-basis: 150px;
        background-color: #ff4466;
    }
    .two {
        max-width: 50px;
        width: 100px;
        flex-basis: 200px;
        background-color: #42b989;
    }
    .three {
        width: 100px;
        background: #61daff;
    }

效果:

我们可以看出优先级比较是: min/max-width > flex-basis > width

  • align-self

该属性可以控制单个元素和其他元素不相同的方式对齐,会覆盖父元素的align-items属性,默认为auto继承父元素,如果没有父元素则为stretch

.item {
	align-self: "auto" | "flex-start" | "flex-end" | "center" | "stretch" | "baseline"
}

该属性主要应用于子元素上,其特征除了auto有点特殊,其余和align-items完全一致。

浏览器支持

实际使用

我们在日常的开发中,太多太多的地方用到了布局的概念,顶部或者底部导航我们有了flex后就显得十分的简单,直接在content部分设置为flex: 1 === flex: 1 1 0%,这样这个唯一可以伸缩的空间就会把我们的footer推到我们的底部去啦~ 更多的比如开头说道的水平垂直居中,以及一些媒体对象的处理,都会用到我们的flex,所以说这一块还是有必要好好的思考一下的~

写在后面

(个人学习笔记,grid下次更新~)

参考资料

Flex布局教程 阮一峰

Flex MDN

深入理解 flex-grow、flex-shrink、flex-basis