array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 Flexbox 布局的正确使用方法 - 爱码网

Flexbox 布局的正确使用方法

 

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

 

Flexbox兼容性

 

PC端的兼容性

Flexbox 布局的正确使用方法

 

移动端的兼容性

 

 

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

 

Flexbox新旧属性

 

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

 

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

 

Flexbox 布局的正确使用方法

 

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

 

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

 

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

 

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

 

不同点:

 

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

 

Flexbox 布局的正确使用方法

 

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

 

Flexbox 布局的正确使用方法

 

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

 

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

 

不同点:

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

 

Flexbox 布局的正确使用方法

 

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

 

Flexbox 布局的正确使用方法

 

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);

    }

}

 

Flexbox 布局的正确使用方法

 

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

对应着公式一步步计算:

 

// 项目容器宽度

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上的盒子模型来看看是否正确

 

Flexbox 布局的正确使用方法

 

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上的盒子模型来看看是否正确

 

Flexbox 布局的正确使用方法

 

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

 

Flexbox 布局的正确使用方法

 

伸缩项目压缩的计算方式和拉伸的不一样,是因为压缩会有极端情况,我们把第一个伸缩项目的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);

    }

}

 

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

 

Flexbox 布局的正确使用方法

 

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

 

// 项目容器宽度

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

 

Flexbox 布局的正确使用方法

 

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

 

Flexbox 布局的正确使用方法

 

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

 

Flexbox 布局的正确使用方法

 

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

 

Flexbox 布局的正确使用方法

 

margin折叠

 

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

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

 

旧版Flexbox的BUG

 

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

 

 

相关文章: