想象一雙結實而富有彈性的大腿:理解 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
相關文章
相關標籤/搜索