想象一双结实而富有弹性的大腿:理解 Flexbox 布局

说明

本站不支持 CodePen 的脚本插入,能够到个人博客阅读直接显示示例代码的版本。css

Flexbox 让人困惑

有不少谈及 Flexbox 的文章,但依然有很多前端对此感到困惑。一方面,flex 相关的 CSS 属性繁多,影响到的具体效果也包含多个方面;另外一方面,CSS 可使用 Shorthand properties 风格的写法(例如最多见的 background: url(images/bg.gif) no-repeat left top;),很容易让新手弄不清具体含义。前端

这篇文章要讲的 Flexbox 固然仍是 CSS3 规范中的弹性盒模型,不过写出前面一段,是由于我但愿这篇文章能够解决那些问题——简单说,就是 Flexbox 让人困惑这样的问题。解决的方法,就是理解它css3

何时,咱们会想到弹性

为了理解弹性盒模型,先要从古龙的笔法开始。古龙是台湾的武侠小说大师,成就仅次于金庸。古龙描写的一些人物,很是深刻人心,其犀利以及使人难忘的程度,甚至超过金庸。好比,有一位中年男性,在整部小说里,他的手很是重要,古龙对此有屡次描写——“他的手指修长而有力”。而在不止一本书中,不止一两个情节中,有几位青年女性,她们的腿很是重要,古龙的描述是——“大腿结实而富有弹性”,或者“修长结实而富有弹性”。ide

轻呼一口气,思考一下,为何描写手指的时候要说“修长而有力”,而描写大腿倒是“结实而富有弹性”?这真是一个很是值得思考的问题。实际上,人的腿也能够是“修长而有力”的;并且,人的手指也是有弹性的。但古大师的描写绝非随意为之,其中的道理,能够随便找些包含大腿的人物画看一看,或者只是想象一下——一幅人物画中,手指的面积有多大?除非为了强调手部而加了特技,不然手指所占的面积是很小的;而大腿,在一幅正常的人物画中,是充满空间的。这里说的充满,固然并非指彻底占满空间,也不是上下左右必定没有空隙。布局

记住这种“充满”,如今思考一下 Flexbox。何时,咱们会想到或者说须要弹性这件事情?答案是当咱们须要“充满”一个容器的时候。带着这种思考,再回到人物画。手指只是在画面的特定位置,解决这种问题,咱们能够简单地用 position: absolute;float: left; 这些属性搞定。而大腿是“充满”画面的,当咱们须要“充满”容器的时候,弹性就很重要!要解决这类问题,咱们应该思考的就不是某个局部的空间,而是空间的分配。包括如何分配容器内的全部盒子,若是空间过大怎么办,若是空间太小怎么办;而在移动端,设备的屏幕尺寸有不少种,问题就变成了空间有时候大、有时候小怎么办。flex

读者应该已经可以想到,弹性盒模型就是为了更方便地解决这些问题而产生的。那么先看一看非弹性的盒子遇到这些场景会有哪些不便。ui

百分比网格

See the Pen understanding-css-flexbox 1: percentage by Alpha Bao (@AlphaBao) on CodePen.flexbox

上面是用浮动和百分比的方式写的横向网格,因为直接给其中一个设置了不一样的高度,很明显,能够看出,四个格子的高度是不一样的。若是格子的高度变化是由其中的内容引发,也会存在一样的问题。url

另外,示例之中是四个格子,因此设置每一个格子为 width: 25%; 就可让它们横向充满父级容器,并且大小变化也没有影响。但若是须要渲染的数据是动态的,写成具体某个百分比显然就不行了。即元素个数变化时每一个元素的百分比也须要变化,就须要修改 CSS。spa

这些问题都是由于这样的盒模型是没有“弹性”的,若是有弹性,就可让布局按照咱们但愿的方式渲染。

Flex 网格

.container {
  display: flex;
}复制代码

弹性盒模型带来了 Flexbox 布局,像上面这样,给充当 container 的盒子设置 display: flex; 就可让它的子元素弹性排列,默认是横向的,由于 flex-direction: row; 是默认值,咱们先不关心它。先看一下最经常使用的属性 flex-grow

flex-grow

See the Pen understanding-css-flexbox 2: flex-grow by Alpha Bao (@AlphaBao) on CodePen.

能够看到其中一个是 flex-grow: 2;,其余都是 1,意思是这些子元素将充满容器,它们将容器分红了若干份,每一个 flex-grow: 1; 元素占据一份,flex-grow: 2; 的占两份,由于它的 flex-grow 值是其余元素的两倍。也就是说,flex-grow 决定子元素如何膨胀。在 Flexbox 的充满/填充策略中,flex-grow 影响的是元素膨胀到多大。注意这实际上是如何分配父级容器空间的问题,并且是容器大小会改变的情形下,因此具体子元素的大小是取决于空间剩余状况的,并非 flex-grow 越大,元素就必定会越大。

flex-basis

再看 flex-basis 属性,它是指元素的初始大小,上一个例子中,只设置了 flex-grow,因此初始大小就是元素内容决定的,若是元素没有内容,大小就是零。

See the Pen understanding-css-flexbox 3: flex-basis by Alpha Bao (@AlphaBao) on CodePen.

flex-basis 的默认值是 auto,是指元素的大小(本文中指的是元素横向的长度,由于 flex-direction 默认值是 row,这决定了 main axis(主轴)是横向的,即容器的子元素横向排列)根据元素的长度属性或者由内容决定。能够是具体长度值也能够是百分比。

.c3 {
  width: 15em;
  flex-basis: auto;
}复制代码

此时初始宽度是 15em,也能够写为下面这样:

.c3 {
  flex-basis: 15em;
}复制代码

两种写法效果相同。

计算完初始大小,再根据容器空间剩余状况,继续完成“充满”容器这件事情。若是先只考虑空间还有剩余的状况,前面提到的 flex-grow 属性就开始起做用,使元素膨胀,直到充满容器。

flex-shrink

前面考虑的都是空间还有剩余的状况,接下来考虑一下空间不足的状况。首先要弄清楚,具体怎样会致使空间不足。

See the Pen understanding-css-flexbox 4: flex-shrink by Alpha Bao (@AlphaBao) on CodePen.

能够看到,经过设置宽度或者由内容填充,此时可能致使空间不足。此时 flex-shrink 会起做用。首先计算初始大小,再考虑空间不足的状况,这时候根据 flex-shrink 的值决定如何收缩各个元素,数值越大,相对其余元素的收缩倍数就越大。flex-shrink 默认值是 1,即不改变这个属性值的状况下,空间不足时每一个元素的收缩程度相同。若是改成 0,则不收缩。

flex

flex 是上面三者的简写形式(这类写法的属性就是 Shorthand properties)。

.item {
  flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}复制代码

See the Pen understanding-css-flexbox 5: flex by Alpha Bao (@AlphaBao) on CodePen.

上面的每一个子元素都设置了 flex: 1 1 100px;,即初始宽度值是 100px,若是空间剩余,每一个元素平均分配,若是空间不足,每一个元素同等程度的收缩。flex: 0 1 auto;flex 属性的默认值,表示不膨胀(若是都不膨胀,那么有剩余空间也不会充满),收缩因数是 1,元素在主轴方向上的长度取决于长度值或者元素内容。

经过上面几个例子,能够看得出在大小会动态变化的父级容器里面,这种分配空间的策略优点很明显,这就是弹性带来的便利。flex 是实际开发中经常使用的写法,它的内容其实就是如何“充满”容器空间的策略,是 Flexbox 中最重要的部分。

结束语

本文只谈及了 flex-grow flex-shrink flex-basis,关于 Flexbox,还有不少内容。好比决定缠绕方式的 flex-wrap,它的效果相似 float,还有 justify-content,它决定元素在 main axis(主轴)方向的对齐方式,align-self 则决定 cross axis(垂直的交叉轴)方向(在例如主轴是水平方向,而各个元素具备不一样的高度这类状况下起做用)。属性名有点乱,不过它们都是围绕充满弹性扩展开的。只要结合对“充满”空间这件事情的想象,理解了弹性的含义,就弄清了目标与方法,应该能比较容易地学会并运用 Flexbox 了。

如上所见,本文所谈的,并非大腿这件事情,若是你想看“真正的”大腿,能够读一读古龙的《多情剑客无情剑》、《午夜兰花》、《长生剑》以及《萧十一郎》。

扩展阅读

  1. A Complete Guide to Flexbox
  2. A Visual Guide to CSS3 Flexbox Properties
相关文章
相关标签/搜索