zoukankan      html  css  js  c++  java
  • Flexbox 布局的正确使用方法

    Flexbox 布局的正确使用方法

     

    在项目中,我们还会大量使用到flexbox的新旧属性,但大多数人一般只会写新属性,旧属性交由autoprefixer处理,但其实完成同样功能的新旧属性表现形式却不尽相同。还有部分人只使用“万能”的flex:number属性为伸缩项目分配空间,但有些特殊情景却无法满足,此文为此梳理了flexbox的新旧属性区别和分配空间的原理,为大家用flexbox布局的项目通通渠。

    Flexbox兼容性

    PC端的兼容性

    移动端的兼容性

    如上图,为了兼容IE10-11和Android4.3-,UC,我们仍需要使用Flexbox的旧属性。

    Flexbox新旧属性

    Flexbox的新属性提供了很多旧版本没有的功能,但是目前Android4.x和UC仍有一定市场占有率需要兼容,因此目前只使用新旧属性都有的功能。

    能实现相同功能的Flexbox新旧属性如下表:

    但想象是美好的,现实是残酷的,新旧属性里有那么几个顽固分子并不能乖乖的表现的一样,总有那么一点不同。

    下面我们来看看是哪些新旧属性有不同:

    flex-direction:row-reverse vs box-orient:horizontal;box-direction:reverse

    相同点:改变主轴方向和伸缩项目的排列顺序;在ltr下伸缩项目从右到左排列。

    不同点:

    flex-direction:row-reverse:第一个伸缩项目向主轴起点对齐

    box-orient:horizontal;box-direction:reverse:最后一个伸缩项目向主轴终点对齐

    flex-direction:column-reverse vs box-orient:vertical;box-direction:reverse

    相同点:改变主轴方向和伸缩项目的排列顺序;在ltr下伸缩项目从下到上排列。

    不同点:

    flex-direction:column-reverse:第一个伸缩项目向主轴起点对齐。

    box-orient:vertical;box-direction:reverse:最后一个伸缩项目向主轴终点对齐。

    oreder:integer vs box-ordinal-group:integer

    相同点:定义伸缩项目显示顺序。

    不同点:

    oreder:integer:默认值为0;可以为负值。

    box-ordinal-group:integer:默认值为1;取值大于1。

    flex-grow:number vs box-flex:number

    相同点:定义伸缩项目的扩展因素。

    不同点:box-flex:number同时定义了伸缩项目的缩小因素。

    flex-shrink:number vs box-flex:number

    相同点:定义伸缩项目的缩小因素。

    不同点:box-flex:number同时定义了伸缩项目的扩展因素。

    Flexbox分配空间原理

    影响Flexbox布局分配空间的属性有三个,分别是flex-grow、flex-shrink和flex-basis。

    • flex-grow:当伸缩项目在主轴方向的总宽度

    • flex-shrink:当伸缩项目在主轴方向的总宽度 > 伸缩容器,伸缩项目根据缩小因素分配总宽度超出伸缩容器的空间。

    • flex-basis:伸缩基础,在进行计算剩余空间或超出空间前,给伸缩项目重新设置一个宽度,然后再计算。

    我们先来看看如何计算计算拉伸后的伸缩项目宽度,先简单明了的给个公式,再通过栗子来验证。

    伸缩项目扩展宽度 = (项目容器宽度 – 项目宽度或项目设置的flex-basis总和) * 对应的flex-grow比例

    拉伸后伸缩项目宽度 = 原伸缩项目宽度 + 扩展宽度

    .flexbox-wrap{

        width:550px;

        display: flex;

    }

    .flexbox-item{

        &:nth-child(1){

            width:60px;

        }

        &:nth-child(2){

            width:70px;

        }

        &:nth-child(3){

            flex-basis:80px;

        }

        &:nth-child(4){

            flex-basis:90px;

        }

        &:nth-child(5){

             flex-basis:100px;

        }

    }

    @for $i from 1 through 5 {

        .flexbox-item:nth-child(#{$i}){

            flex-grow: $i;

            background-color: rgba(35 * (6-$i), 20 * $i, 35 * $i,1);

        }

    }

    我们来计算一下上面栗子中第一个伸缩项目拉伸后的宽度。

    对应着公式一步步计算:

    // 项目容器宽度

    container = 550

    // 项目宽度或项目设置的flex-basis总和

    itemSum = 60 + 70 + 80 + 90 + 100 = 400

    // 第一个伸缩项目对应的flex-grow比例

    flexRatio = 1 / ( 1 + 2 + 3 + 4 + 5 ) = 1/15

    // 第一个伸缩项目扩展宽度

    extendWidth = ( 550 - 400 ) * 1/15 = 10

    // 第一个伸缩项目拉伸后的宽度

    itemWidth = 60 + 10 = 70

    计算后得到第一个伸缩项目拉伸后的宽度是70px,我们通过chrome上的盒子模型来看看是否正确

    chrome计算的结果和我们计算的结果是一致的。

    根据拉伸的计算公式是不是很容易就能推演出压缩的计算公式呢?

    伸缩项目缩小宽度 = (项目宽度或项目设置的flex-basis总和 – 项目容器宽度) * 对应的flex-shrink比例

    压缩后伸缩项目宽度 = 原伸缩项目宽度 – 缩小宽度

    继续用个栗子来验证公式是否正确

    .flexbox-wrap{

        width:250px;

        displayflex;

    }

    .flexbox-item{

        &:nth-child(1){

            width:60px;

        }

        &:nth-child(2){

            width:70px;

        }

        &:nth-child(3){

            flex-basis:80px;

        }

        &:nth-child(4){

            flex-basis:90px;

        }

        &:nth-child(5){

             flex-basis:100px;

        }

    }

    @for $i from 1 through 5 {

        .flexbox-item:nth-child(#{$i}){

            flex-shrink$i;

            background-colorrgba(35 * (6-$i), 20 * $i, 35 * $i,1);

        }

    }

    我们来计算一下上面栗子中第一个伸缩项目压缩后的宽度。

    对应着公式一步步计算:

    // 项目容器宽度

    container = 250

    // 项目宽度或项目设置的flex-basis总和

    itemSum = 60 + 70 + 80 + 90 + 100 = 400

    // 第一个伸缩项目对应的flex-shrink比例

    flexRatio = 1 / ( 1 + 2 + 3 + 4 + 5 ) = 1/15

    // 第一个伸缩项目缩小宽度

    extendWidth = ( 400 - 250 ) * 1/15 = 10

    // 第一个伸缩项目压缩后的宽度

    itemWidth = 60 - 10 = 50

    计算后得到第一个伸缩项目压缩后的宽度是50px,我们通过chrome上的盒子模型来看看是否正确

    chrome计算的结果和我们计算的结果不一样。

    伸缩项目压缩的计算方式和拉伸的不一样,是因为压缩会有极端情况,我们把第一个伸缩项目的flex-shrink修改为10,此时缩小宽度为( 400 - 250 ) * ( 10 / 24) = 62.5,缩小的宽度比原宽度要大,计算的压缩后的宽度变成了负数。

    为了避免这种极端情况,计算缩小比例是要考虑伸缩项目的原宽度。

    正确的公式是这样的

    伸缩项目缩小宽度 = (项目宽度或项目设置的flex-basis总和 – 项目容器宽度) (对应的flex-shrink 项目宽度或项目设置的flex-basis比例)

    压缩后伸缩项目宽度 = 原伸缩项目宽度 – 缩小宽度

    对应着公式一步步计算:

    // 项目容器宽度

    container = 250

    // 项目宽度或项目设置的flex-basis总和

    itemSum = 60 + 70 + 80 + 90 + 100 = 400

    // 第一个伸缩项目对应的flex-shrink比例

    flexRatio = (1*60) / (1*60+2*70+3*80+4*90+5*100) = 6/130

    // 第一个伸缩项目缩小宽度

    extendWidth = ( 400 - 250 ) * 6/130 ≈ 6.922

    // 第一个伸缩项目压缩后的宽度

    itemWidth = 60 - 6.922 = 53.078

    计算后得到第一个伸缩项目压缩后的宽度是53.078px,和chrome上的盒子模型是一样的。

    Flexbox属性缩写陷阱

    上面介绍的flex-grow、flex-shrink和flex-basis有一个缩写的写法flex。

    flex: flex-grow [flex-shrink] [flex-basis]

    flex各种缩写的值

    • flex: initial == flex: 0 1 auto

    • flex: none == flex: 0 0 auto

    • flex: auto == flex: 1 1 auto

    • flex: number == flex: number 1 0%

    在实际项目中,会直接写使用缩写的flex来给伸缩项目分配空间,但是使用缩写属性会留下一些陷阱,导致表现的结果不尽如人意。

    分别使用flex和flex-grow来把伸缩项目拉伸填满容器,看看表现的差异。

    首先看看使用flex-grow拉伸伸缩项目的效果

    .flexbox-wrap{

        width:550px;

        display: flex;

    }

    .flexbox-item{

        flex-grow:1;

        &:nth-child(1){

            width:60px;

        }

        &:nth-child(2){

            width:70px;

        }

        &:nth-child(3){

            width:80px;

        }

        &:nth-child(4){

            width:90px;

        }

        &:nth-child(5){

             width:100px;

        }

    }

    @for $i from 1 through 5 {

        .flexbox-item:nth-child(#{$i}){

            background-color: rgba(35 * (6-$i), 20 * $i, 35 * $i,1);

        }

    }

    每个伸缩项目在原宽度上拉伸相同的宽度

    通过上面的计算拉伸后的伸缩项目宽度,可以计算第一个伸缩项目拉伸后的宽度

    // 项目容器宽度

    container = 550

    // 项目宽度或项目设置的flex-basis总和

    itemSum = 60 + 70 + 80 + 90 + 100 = 400

    // 第一个伸缩项目对应的flex-grow比例

    flexRatio = 1 / ( 1 + 1 + 1 + 1 + 1 ) = 1/5

    // 第一个伸缩项目扩展宽度

    extendWidth = ( 550 - 400 ) * 1/5 = 30

    // 第一个伸缩项目拉伸后的宽度

    itemWidth = 60 + 30 = 90

    然后我们把flex-grow:1替换成flex:1,下面是表现的效果,伸缩项目拉伸后的宽度变成一样了。

    从chrome的盒子模型可看到伸缩项目拉伸后宽度变成了110px,伸缩容器等分了容器的宽度。

    flex:1展开后是flex:1 1 0%,flex-grow:1相当于flex:1 1 auto,两者的区别在于flex-basis的值不同。flex:1为项目宽度重新设置了宽度为0,所以可分配空间为整个容器,从公式计算上可以更直观理解:

    // 项目容器宽度

    container = 550

    // 项目宽度或项目设置的flex-basis总和

    itemSum = 0 + 0 + 0 + 0 + 0 = 0

    // 第一个伸缩项目对应的flex-grow比例

    flexRatio = 1 / ( 1 + 1 + 1 + 1 + 1 ) = 1/5

    // 第一个伸缩项目扩展宽度

    extendWidth = ( 550 - 0 ) * 1/5 = 110

    // 第一个伸缩项目拉伸后的宽度

    itemWidth = 0 + 110 = 110

    需要注意的Flexbox特性

    无效属性

    • column-*在伸缩容器无效

    • float和clear在伸缩项目无效

    • vertical-align在伸缩项目无效

    • ::first-line and ::first-letter在伸缩容器无效

    伸缩容器中的非空字符文本节点也是伸缩项目

    1 2 我是个假文本 3 4 5

    margin折叠

    • 伸缩容器和伸缩项目的margin不会折叠

    • 伸缩项目间的margin不会折叠

    旧版Flexbox的BUG

    伸缩项目为行内元素要加display:block;或display:flex

     
    夫君子之行,静以修身,俭以养德。非淡泊无以明志,非宁静无以致远。夫学须静也,才须学也,非学无以广才,非志无以成学。慆慢则不能励精,险躁则不能冶性。年与时驰,意与日去,遂成枯落,多不接世,悲守穷庐,将复何及!
  • 相关阅读:
    【贪心】【堆】Gym
    【并查集】Gym
    【拓扑排序】【bitset】Gym
    【递归】【线段树】【堆】AtCoder Regular Contest 080 E
    【二分图】【并查集】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem L. Canonical duel
    【动态规划】【滚动数组】【bitset】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem J. Terminal
    【二分】【字符串哈希】【二分图最大匹配】【最大流】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem I. Minimum Prefix
    【枚举】【最小表示法】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem F. Matrix Game
    【推导】【构造】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem E. Space Tourists
    【推导】【贪心】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem D. Clones and Treasures
  • 原文地址:https://www.cnblogs.com/lzg9/p/7135874.html
Copyright © 2011-2022 走看看