最近想更改一下博客首页的布局样式,添加几个侧栏,就去看了看常见的布局方式,什么「双飞翼布局」「圣杯布局」也就两侧固定中间自适应的三栏布局方案。不过我以前一直都是用的 Flex 布局,Flex 布局是否是也能够作到呢,网上搜索一番,代码以下:css
<html lang="en">
<body>
<div style="display: flex;">
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
</div>
</body>
<style> .a { background-color: thistle; width: 20%; } .b { background-color: tomato; flex: 1; } .c { background-color: violet; width: 100px; } .a, .b, .c { height: 100px; } </style>
</html>
复制代码
这样一看是否是很是简单,比前文介绍的两种布局优雅多了,可是让我困惑的是第 17 行的 flex: 1
,在阮一峰老师的博客上是这样描述的html
flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。wordpress
Google 搜索出来的结果也都是说 flex 属性就是简写,那为何 flex:1
能够实现中间部分自适应,这黑箱通常的原理一直困扰着我,flex 究竟是怎么起做用的呢,下面咱们来详细研究研究。(关于这几个属性的意义能够看阮一峰老师的博文)) 布局
首当其冲的困惑就是 flex
属性是flex-grow
,flex-shrink
和flex-basis
的缩写。那么为何会有flex:1
这种后面接一个数字的呢?这就不得不提到 flex 的语法,不知道同窗们有没有看 CSS 语法的习惯,查询 MDN 可知其正式语法为flex
none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]ui
感受看起来眼都花了,这怎么理解嘛,别急咱们一个一个来分析,|
这个符号表示排他,能够为后者或者前者,因此这就有两种语法了this
flex: none;
flex: [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
复制代码
接下来就是方括号[]
,表示范围,也就是说 flex 属性后面跟随的以三个数就是表示这三个属性的,好比:flexbox
{
flex:1 1 100px
}
/* 等于 */
{
flex-grow:1
flex-shrink:1
flex-basis:100px
}
复制代码
再看符号||
表示的意思是「或者」,能够为 flex: [ <'flex-basis'> ]
或者为flex: [ <'flex-grow'> <'flex-shrink'>]
,也能够共存。而符号?
表示 0 或者 1,也就是说flex-shrink
无关紧要,这样一来一共是有如下几种组合方式。spa
flex: [ <'flex-basis'> ]
flex: [ <'flex-grow'>]
flex: [ <'flex-grow'> <'flex-shrink'>]
flex: [ <'flex-grow'> <'flex-basis'> ]
flex: [ <'flex-grow'> <'flex-shrink'><'flex-basis'> ]
复制代码
能够发现 flex 属性后面跟一个值的状况就是 1 和 2 行,而 flex-basis
的单位是长度单位,因此flex:1
就至关于 flex-grow : 1
,原来如此,这样设置就使元素填满剩余空间。从完成「双飞翼布局」角度来讲这个疑问好像已经获得了解答,可是 flex 属性的这三个值却远远没有这么简单。
3d
简单介绍一下这三个属性
0
,多余空间不分配。1
,空间不足要分配。演示代码以下:
<html>
<body>
<div class="flex">
<div class="a"></div>
</div>
</body>
<style> .flex { display: flex; background-color: violet; } .a { background-color: thistle; width: 100px; flex-grow: 0.1; height: 100px; } </style>
</html>
复制代码
元素 a 本来的宽度值为 100px ,而后手动将 flex 宽度设置为 500px,这个时候再查看元素 a 的实际宽度,为 140px
分配空间(140-100 = 40)=可分配空间(500-100=400px)* flex-grow (0.1)
因此元素实际宽度 = 自身长度(100)+分配空间(40)= 140px
<html lang="en">
<body>
<div class="flex">
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
</div>
</body>
<style> .flex { display: flex; background-color: violet; } .a { background-color: thistle; width: 100px; flex-grow: 1; } .b { background-color: tomato; width: 100px; flex: 2; } .c { background-color: violet; width: 100px; flex: 3; } .a, .b, .c { height: 100px; } </style>
</html>
复制代码
同样手动将 flex 元素宽度设置为 500px,咱们来看一下三个元素的实际宽度
咱们来看看实际宽度是怎么计算出来的
a 实际宽度 = 可分配空间(500-300=200)* (1 / 1+2+3)+设置宽度(100)= 33.33 + 100 =133.33
其余几个也是这样计算的,应该仍是挺容易理解的吧
<html lang="en">
<body>
<div class="flex">
<div class="a">a</div>
<div class="b">b</div>
<div class="c">c</div>
</div>
</body>
<style> .flex { display: flex; background-color: violet; } .a { background-color: thistle; width: 100px; flex-grow: 0.1; } .b { background-color: tomato; width: 100px; flex-grow: 0.2; } .c { background-color: aqua; width: 100px; flex-grow: 0.3; } .a, .b, .c { height: 100px; } </style>
</html>
复制代码
能够看到元素们并无占满空间, 看看实际宽度
a 实际宽度 = 实际分配空间 * (0.1 / 0.1+0.2+0.3)+设置宽度(100)= 20 + 100 =120
和大于 0 状况相比较的话仅仅是「可分配空间」->「实际分配空间」,而上文提到过
实际分配空间 = 可分配空间 * flex-grow 之和
也就是本实例中的实际分配空间为 200 * (0.1+0.2+0.3)=120,其实就是把可分配空间与 flex-grow 之和相乘,而后按比例分配空间。
这种状况其实想想就能得出结论,和大于 1,就是占满可分配空间,而后按照比例分配
到这咱们就能够得出结论了,其实这种对单个 flex-grow 值进行分类的方式是错误的,而应该按照全部 flex-grow 相加是否大于 1,由于大于 1 就将全部剩余空间按比例分配,小于 1 则须要先计算实际分配空间再按比例分配,不会占满全部剩余空间。
flex-shrink 属性是当父元素长度不够的时候各元素的缩小规则,默认为 1 ,也就是你们都按照相同比例缩小,至于具体怎么缩小,是否是也像 flex-grow 那样按照数值等比例缩小呢,并无那么简单,咱们先来看个实例,元素宽度相等的状况下:
<html lang="en">
<body>
<div class="flex">
<div class="a">a</div>
<div class="b">b</div>
<div class="c">c</div>
</div>
</body>
<style> .flex { display: flex; background-color: violet; } .a { background-color: thistle; width: 200px; flex-shrink: 1; } .b { background-color: tomato; width: 200px; flex-shrink: 2; } .c { background-color: aqua; width: 200px; flex-shrink: 3; } .a, .b, .c { height: 100px; } </style>
</html>
复制代码
手动将 flex 元素宽度设置为 400px ,这个时候看三个子元素的实际宽度
很容易能够经过计算得出
元素 c 收缩长度 = 实际长度(200) - 超出长度(600-400)*(3/1+2+3) = 100
此时计算方式确实和 flex-grow 如出一辙,可是当各元素长度不同的时候呢?
<html lang="en">
<body>
<div class="flex">
<div class="a">a</div>
<div class="b">b</div>
<div class="c">c</div>
</div>
</body>
<style> .flex { display: flex; background-color: violet; } .a { background-color: thistle; width: 100px; flex-shrink: 1; } .b { background-color: tomato; width: 200px; flex-shrink: 2; } .c { background-color: aqua; width: 300px; flex-shrink: 3; } .a, .b, .c { height: 100px; } </style>
</html>
复制代码
a 收缩长度 = 14.28
b 收缩长度 = 57.14
c 收缩长度 = 128.58
能够看到收缩长度并不和元素各自的 flex-shrink 值成正比,查阅 W3 文档和 MDN 也没有发现详细的计算方式,Google 了一大圈终于破解了这个秘密,原来与 flex-grow 延伸长度只与 flex-grow 值相关不同,flex-shrink 元素的收缩长度不只和 flex-shrink 相关,还与元素自身大小相关,具体计算方式以下:
收缩长度 = (元素宽度 * flex-shrink) / (100 * 1+200 * 2+300 * 3) * 须要收缩宽度
代入本例计算一下:
a 元素收缩长度 = 100 * 1/ (100 * 1+200 * 2+300 * 3) * ( 600-400 ) = 14.28 =100 - 85.72
与实际状况相复合,flex-shrink 了解完毕。 等着! 忘了 flex-grow 里面当 flex-grow 相加小于 1 这种情形了吗,那么在这是怎么表现的呢,看看实例:
<html lang="en">
<body>
<div class="flex">
<div class="a">a</div>
<div class="b">b</div>
<div class="c">c</div>
</div>
</body>
<style> .flex { display: flex; background-color: violet; } .a { background-color: thistle; width: 100px; flex-shrink: 0.1; } .b { background-color: tomato; width: 200px; flex-shrink: 0.2; } .c { background-color: aqua; width: 300px; flex-shrink: 0.3; } .a, .b, .c { height: 100px; } </style>
</html>
复制代码
能够很直观的看到,三元素长度相加是大于 flex 元素长度的,也就是说并无「彻底」收缩,各个元素长度为
实际总收缩长度 = 须要收缩长度 * flex-shrink 之和
在本例中,实际收缩长度 = 200 * 0.6 = 120 =600 - 480(收缩后总长度),与实际符合,得出实际收缩长度以后各元素收缩长度就和上文提到的方法是同样的了。
虽然上面的计算公式看起来比较复杂,其实理解了以后仍是比较简单的,借用知乎@谢然的总结:
若是全部元素的 flex-grow/shrink 之和大于等于 1,则全部子元素的尺寸必定会被调整到适应父元素的尺寸(在不考虑 max/min-width/height 的前提下),而若是 flex-grow/shrink 之和小于 1,则只会 grow 或 shrink 全部元素 flex-grow/shrink 之和相对于 1 的比例。grow 时的每一个元素的权重即为元素的 flex-grow 的值;shrink 时每一个元素的权重则为元素 flex-shrink 乘以 width 后的值。
说到 flex 布局,谁还不能说上几句,仿佛全世界都在用 flex 布局了,可是你真的了解吗,我其实最先开始接触 CSS 的时候就是使用的 flex 布局,垂直居中什么的玩得特别 6 ,可是在这几天才对 flex 属性有了真正的认识。这也让我认识到不求甚解在技术界是一种陋习,直接照着写上一句 flex:1
确实很容易实现三栏布局,可是当需求发生变化就懵逼了。只有真正了解了底层原理才能为所欲为的实现心中所想。
还有一点就是你的信息来源渠道很大程度上决定了你信息的准确性与真实性,官网文档永远是最正确最完善的,尽可能去信息源头寻找答案。强如阮一峰老师的flex教程中对于 flex 属性的描述也不够清楚,Google 永远都比百度好使。
到这咱们的深刻挖掘就告一段落了,可能你发现不是还有 flex-basis 没有讲吗,这是由于 flex-basis 也是一个有很是多细节的属性,可是其细节又与这两个须要计算的不同,值得单独写一篇文章来进行介绍,在下篇文章中咱们再来细聊。