很長一段時間, 我知道有flex
這個佈局方式, 可是始終沒有去學它. 3點緣由:css
最近因爲開發須要, 學習了下WeUI的實現, 發現裏面大量使用了flex
佈局, 因而決定學習一下.html
flex
Flexbox Layout
, 官方名爲CSS Flexible Box Layout Module, 意爲"彈性佈局", 是CSS3中引入的一種更加靈活高效的佈局/對齊/排序方式(還有一種更適合大型佈局的網格佈局CSS Grid Layout Module). flex
是flexible
的縮寫.css3
任何一個容器均可以指定爲flex佈局。瀏覽器
.box { display: flex; }
行內元素也可使用flex佈局。微信
.box { display: inline-flex; }
採用flex佈局的元素被稱爲flex容器 (flex container), 它的子元素即爲flex元素 (flex item).ide
flex容器中包含兩個相互垂直的軸, 即主軸 (main axis)和副軸 (cross axis).佈局
flex元素沿主軸從主軸起點 (main start)到主軸終點 (main end)依次排布.學習
若是flex容器包含多行flex元素, 則flex行 (flex lines)沿副軸從副軸起點 (cross start)到副軸終點 (cross end)依次排布.flex
單個flex元素佔據的主軸空間叫作主軸長度 (main size), 佔據的副軸空間叫作副軸長度 (cross size).ui
Getting Dicey With Flexbox中提到:
There's a popular myth floating around that flexbox isn't ready for prime time. Wrong! 93% of people are now running a browser that supports flexbox. That's better than the support for the HTML5
<video>
element.
前一段時間同事作過video
相關的開發, 踩到各類坑, 所以我知道video
的支持不那麼好, 特別是在Android上. 讓我驚奇的是flex
居然比video
的支持更好?
從CanIUse的數據來看, flex
的支持度是: 82.65% (支持) + 14.17% (部分支持) = 96.81%
, 而video
的支持度是: 92.48%
. 瀏覽器對flex
的支持好像並無特別好...
可是有微信的WeUI使用了flex
佈局, 我以爲在移動端flex
應該仍是支持度比較高的.
因此, 若是你是作移動端開發的, 能夠優先考慮flex
.
下面就開始介紹與flex
佈局相關的屬性. 以做用對象分爲兩組, 第一組做用於flex容器, 第二組做用於flex元素.
注意: 如下屬性值均可以有initial
(該屬性的默認值)和inherit
(繼承自父元素), 本處省略.
這類屬性有6種, 分別爲:
屬性 | 含義 |
---|---|
flex-direction |
主軸方向 |
flex-wrap |
換行樣式 |
flex-flow |
前兩個的簡寫形式 |
justify-content |
主軸對齊方式 |
align-items |
單行的副軸對齊方式 |
align-content |
多行的副軸對齊方式 |
注意:
column-*
屬性會失效.::first-line
和::first-letter
虛元素.含義 | 主軸方向 |
可選值 | row | row-reverse | column | column-reverse |
默認值 | row |
row |
direction 爲ltr 時從左向右→, rtl 時從右向左←. |
row-reverse |
direction 爲ltr 時從右向左←, rtl 時從左向右→. |
column |
從上到下↓. |
column-reverse |
從下到上↑. |
注意: row
和row-reverse
受到了direction
屬性(默認值爲ltr
, 可改成rtl
)的影響.
含義 | 換行樣式 |
可選值 | nowrap | wrap | wrap-reverse |
默認值 | nowrap |
nowrap |
不換行 |
wrap |
換行. 行與行從上到下↓排布 |
wrap-reverse |
換行. 行與行從下到上↑排布 |
含義 | flex-direction 和flex-wrap 的簡寫形式 |
可選值 | flex-direction flex-wrap |
默認值 | row nowrap |
含義 | 主軸對齊方式 |
可選值 | flex-start | flex-end | center | space-between | space-around |
默認值 | flex-start |
含義 | 單行的副軸對齊方式 |
可選值 | flex-start | flex-end | center | stretch | baseline |
默認值 | stretch |
含義 | 多行的副軸對齊方式 |
可選值 | stretch | flex-start | center | flex-end | space-between | space-around |
默認值 | stretch |
注意: 此屬性只在flex容器中有多行flex元素時纔有做用.
這類屬性有6種, 分別爲:
屬性 | 含義 |
order |
排列順序 |
align-self |
flex元素的副軸對齊方式. 對應於flex容器的align-items . |
flex-grow |
放大比例 |
flex-shrink |
縮小比例 |
flex-basis |
初始大小 |
flex |
上面三個的簡寫形式 |
注意: flex元素的float
, clear
和vertical-align
會失效.
含義 | 排列順序. 沿着主軸, flex元素按order 的增序排列. |
可選值 | <integer> |
默認值 | 0 |
含義 | flex元素的副軸對齊方式. 對應於flex容器的align-items . |
可選值 | auto | stretch | center | flex-start | flex-end | baseline |
默認值 | auto |
當flex元素有父元素時, 它的align-self: auto
即爲父元素的align-items
屬性; 不然(無父元素時), 至關於stretch
.
含義 | 放大比例 |
可選值 | <number> (非負值) |
默認值 | 0 |
當有剩餘空間時, flex元素會根據flex-grow
按比例分配剩餘空間.
默認值0
表明, 即便有剩餘空間, 該flex元素也不放大.
含義 | 縮小比例 |
可選值 | <number> (非負值) |
默認值 | 1 |
當flex容器空間不足時, flex元素會根據flex-shrink
按比例縮小.
flex-shrink
爲0
則表示, 即便flex容器空間不足, 該flex元素也不縮小.
含義 | 初始大小 |
可選值 | auto|<length> (非負值) |
默認值 | auto |
flex-basis
定義了分配剩餘空間以前flex元素的初始大小, 可爲長度值(如20%
, 5rem
等)或auto
等關鍵詞.
flex-basis: auto
表示, 以flex元素的主軸長度爲flex-basis
. 若flex元素的主軸長度也是auto
, 則以flex元素內容(即全部子元素)的大小爲flex-basis
.
除了auto
還有content
, max-content
, min-content
和fit-content
關鍵詞, 可是如今瀏覽器對它們的支持太少, 能夠忽略.
含義 | flex-grow , flex-shrink 和flex-basis 的簡寫形式 |
可選值 | none | [ <‘flex-grow’> <‘flex-shrink’>? || <‘flex-basis’> ] |
默認值 | 0 1 auto |
(敲黑板) 同窗們注意, 這裏是重點!
這裏的可選值我參照了W3C flexbox的寫法. 其中:
||
用來分割兩個或多個選項, 從中選取一個或多個, 不限次序.|
用來分割兩個或多個選項, 從中選取一個.[]
只是用來分組的.?
表明可選.舉例來講, a | [ b || c ]
包含的可能狀況有a
, b
, c
, b c
, c b
.
如今回過頭來再看none | [ <‘flex-grow’> <‘flex-shrink’>? || <‘flex-basis’> ]
就清晰多了.
注意, none
是一個特殊值, 至關於0 0 auto
.
另外, 若是flex
中不指定:
flex-grow
成員, 則flex-grow
會被置爲1
.flex-shrink
成員, 則flex-shrink
會被置爲1
.flex-basis
成員, 則flex-basis
會被置爲0
.注意: flex
的初始值是0 1 auto
, 即由每一個flex
因子自己的默認值組成(比方說flex-grow
的默認值就是0
).
可是, 若是利用flex
設置了至少一個flex
因子, 那麼沒被設置的那些flex
因子的默認值(按grow, shrink, basis的順序)分別是1 1 0
.
我來舉幾個栗子.
/* 特殊值none */ flex: none; /* 至關於0 0 auto */ /* 單值,沒有單位的數字,是flex-grow */ flex: 2; /* 至關於 flex: 2 1 0 */ /* 單值,有單位的,寬、高,是flex-basis */ flex: 10em; /* 至關於 flex: 1 1 10em */ flex: 30px; /* 至關於 flex: 1 1 30px */ flex: auto; /* 至關於 flex: 1 1 auto */ flex: content; /* 至關於 flex: 1 1 content */ /* 兩個值:flex-grow flex-basis */ flex: 1 30px; /* 至關於 flex: 1 1 30px */ /* 兩個值:flex-grow flex-shrink */ flex: 2 2; /* 至關於 flex: 2 2 0 */ /* 三個值:flex-grow flex-shrink flex-basis */ flex: 2 2 10%;
W3C建議使用簡寫形式flex
, 由於它能夠方便地應對下面4種常見狀況.
flex: initial |
即flex: 0 1 auto . 以auto 方式計算flex-basis , 不可放大, 可縮小. |
flex: auto |
即flex: 1 1 auto . 以auto 方式計算flex-basis , 可放大, 可縮小. |
flex: none |
即flex: 0 0 auto . 以auto 方式計算flex-basis , 不可放大, 不可縮小. |
flex: <positive-number> |
即<positive-number> 1 0 . flex-basis 爲0 , 以<positive-number> 比例增大, 以1 的比例縮小. |
自此, 咱們已經知道了flex-grow
, flex-shrink
和flex-basis
的做用. 根據這三個值, 計算flex元素的大小隻需三步:
第一步: 計算元素的flex-basis
, 有兩種狀況: 1. 具體的長度值, 或, 2.auto
(即flex元素的大小). (這裏忽略了content
等目前支持還不完善的關鍵詞).
第二步: 計算剩餘空間, 即剩餘空間 = flex容器的內部空間 - flex元素flex-basis值的總和
.
第三步: 按照flex
因子(放大時爲flex-grow
; 縮小時爲flex-shrink
)分配剩餘空間到每一個元素. flex元素的最終大小 = flex-basis - flex-factor * 剩餘空間
.
舉個栗子.
假設flex容器的內部空間爲200px
, flex元素的大小的總和是160px
. 看起來, 還有200 - 160 = 40px
的剩餘空間, 應該放大flex元素, 是否是? 不必定! 要看它們的flex-basis
總和.
假設它們的flex-basis
總和是300px
, 那麼剩餘空間應該是300 - 200 = -100px
. 此時剩餘空間是負數, 應該以flex-shrink
對每一個flex元素在flex-basis
的基礎上進行縮小.
下例中, 全部flex元素自己的大小爲80px
, 元素中爲flex
值.
你能夠看到, 第一行的flex元素由於設置了flex-basis:auto
, 因此它們的flex-basis
就至關於元素大小, 即80px
, 即flex-basis
總和爲160px
, 不足容器的200px
空間, 此時應該放大元素. 但又因爲元素的flex-grow
爲0
, 因此每一個元素分配到0 * 40 = 0px
的剩餘空間, 即不放大.
第二行的flex元素設置了flex-basis:150px
, 因此它們的flex-basis
總和爲300px
, 超過了容器的200px
空間, 故按照flex-shrink
(比例爲1:3
)進行縮小. 因爲剩餘空間爲-100px
, 因此第一個元素應縮小25px
變成125px
, 第二個元素應縮小75px
變成75px
.
絕對flex: 從0開始分配空間.
第一行中flex-basis
爲0
, 表示每一個flex元素的初始大小都視爲0
. 此時, 剩餘空間就是"flex容器的大小".
相對flex: 從flex元素大小開始分配空間.
第二行中flex-basis
爲auto
, 表示每一個flex元素的初始大小都是它自己的大小. 此時, 剩餘空間就是"flex容器的大小 - flex元素大小的總和".
呃... flex的東西仍是挺多的, 特別是flex
因子相關的部分, 得花點兒時間理解.
可是, 我相信學flex是值得的, 誰用誰知道!