flex佈局全解析

CSS Flexbox

前言

很長一段時間, 我知道有flex這個佈局方式, 可是始終沒有去學它. 3點緣由:css

  1. 感受還比較新, 擔憂兼容性很差.
  2. 普通的佈局方式能知足個人絕大多數需求.
  3. 好像蠻複雜的.

最近因爲開發須要, 學習了下WeUI的實現, 發現裏面大量使用了flex佈局, 因而決定學習一下.html

什麼是flex

Flexbox Layout, 官方名爲CSS Flexible Box Layout Module, 意爲"彈性佈局", 是CSS3中引入的一種更加靈活高效的佈局/對齊/排序方式(還有一種更適合大型佈局的網格佈局CSS Grid Layout Module). flexflexible的縮寫.css3

任何一個容器均可以指定爲flex佈局。瀏覽器

.box {
display: flex;
}

行內元素也可使用flex佈局。微信

.box {
display: inline-flex;
}

flex的基本概念

Flex Container and Item

採用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

flex的兼容性

Browser Support

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的支持更好?

Can I use flex

Can I use video

CanIUse的數據來看, flex的支持度是: 82.65% (支持) + 14.17% (部分支持) = 96.81%, 而video的支持度是: 92.48%. 瀏覽器對flex的支持好像並無特別好...

可是有微信的WeUI使用了flex佈局, 我以爲在移動端flex應該仍是支持度比較高的.

因此, 若是你是作移動端開發的, 能夠優先考慮flex.

flex屬性

下面就開始介紹與flex佈局相關的屬性. 以做用對象分爲兩組, 第一組做用於flex容器, 第二組做用於flex元素.

注意: 如下屬性值均可以有initial(該屬性的默認值)和inherit(繼承自父元素), 本處省略.

用於flex容器的屬性

這類屬性有6種, 分別爲:

屬性 含義
flex-direction 主軸方向
flex-wrap 換行樣式
flex-flow 前兩個的簡寫形式
justify-content 主軸對齊方式
align-items 單行的副軸對齊方式
align-content 多行的副軸對齊方式

注意:

  • flex容器的column-*屬性會失效.
  • flex容器沒法擁有::first-line::first-letter虛元素.

flex-direction

含義 主軸方向
可選值 row | row-reverse | column | column-reverse
默認值 row
row directionltr時從左向右→, rtl時從右向左←.
row-reverse directionltr時從右向左←, rtl時從左向右→.
column 從上到下↓.
column-reverse 從下到上↑.

注意: rowrow-reverse受到了direction屬性(默認值爲ltr, 可改成rtl)的影響.

flex-wrap

含義 換行樣式
可選值 nowrap | wrap | wrap-reverse
默認值 nowrap
nowrap 不換行
wrap 換行. 行與行從上到下↓排布
wrap-reverse 換行. 行與行從下到上↑排布

flex-flow

含義 flex-directionflex-wrap的簡寫形式
可選值 flex-direction flex-wrap
默認值 row nowrap

justify-content

含義 主軸對齊方式
可選值 flex-start | flex-end | center | space-between | space-around
默認值 flex-start

justify-content

align-items

含義 單行的副軸對齊方式
可選值 flex-start | flex-end | center | stretch | baseline
默認值 stretch

align-items

align-content

含義 多行的副軸對齊方式
可選值 stretch | flex-start | center | flex-end | space-between | space-around
默認值 stretch

注意: 此屬性只在flex容器中有多行flex元素時纔有做用.

align-content

用於flex元素的屬性

這類屬性有6種, 分別爲:

屬性 含義
order 排列順序
align-self flex元素的副軸對齊方式. 對應於flex容器的align-items.
flex-grow 放大比例
flex-shrink 縮小比例
flex-basis 初始大小
flex 上面三個的簡寫形式

注意: flex元素的float, clearvertical-align會失效.

order

含義 排列順序. 沿着主軸, flex元素按order增序排列.
可選值 <integer>
默認值 0

order

align-self

含義 flex元素的副軸對齊方式. 對應於flex容器的align-items.
可選值 auto | stretch | center | flex-start | flex-end | baseline
默認值 auto

當flex元素有父元素時, 它的align-self: auto即爲父元素的align-items屬性; 不然(無父元素時), 至關於stretch.

align-self

flex-grow

含義 放大比例
可選值 <number> (非負值)
默認值 0

當有剩餘空間時, flex元素會根據flex-grow按比例分配剩餘空間.

默認值0表明, 即便有剩餘空間, 該flex元素也不放大.

flex-grow

flex-shrink

含義 縮小比例
可選值 <number> (非負值)
默認值 1

當flex容器空間不足時, flex元素會根據flex-shrink按比例縮小.

flex-shrink0則表示, 即便flex容器空間不足, 該flex元素也不縮小.

flex-shrink

flex-basis

含義 初始大小
可選值 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-contentfit-content關鍵詞, 可是如今瀏覽器對它們的支持太少, 能夠忽略.

flex

含義 flex-grow, flex-shrinkflex-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-basis0, 以<positive-number>比例增大, 以1的比例縮小.

flex元素大小的計算方法

自此, 咱們已經知道了flex-grow, flex-shrinkflex-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值.

200px
0 1 auto
0 3 auto
0 1 150px
0 3 150px
125px
75px

你能夠看到, 第一行的flex元素由於設置了flex-basis:auto, 因此它們的flex-basis就至關於元素大小, 即80px, 即flex-basis總和爲160px, 不足容器的200px空間, 此時應該放大元素. 但又因爲元素的flex-grow0, 因此每一個元素分配到0 * 40 = 0px的剩餘空間, 即不放大.

第二行的flex元素設置了flex-basis:150px, 因此它們的flex-basis總和爲300px, 超過了容器的200px空間, 故按照flex-shrink(比例爲1:3)進行縮小. 因爲剩餘空間爲-100px, 因此第一個元素應縮小25px變成125px, 第二個元素應縮小75px變成75px.

"絕對flex"和"相對flex"

Relative vs Absolute flex-basis

絕對flex: 從0開始分配空間.

第一行中flex-basis0, 表示每一個flex元素的初始大小都視爲0. 此時, 剩餘空間就是"flex容器的大小".

相對flex: 從flex元素大小開始分配空間.

第二行中flex-basisauto, 表示每一個flex元素的初始大小都是它自己的大小. 此時, 剩餘空間就是"flex容器的大小 - flex元素大小的總和".

結語

呃... flex的東西仍是挺多的, 特別是flex因子相關的部分, 得花點兒時間理解.

可是, 我相信學flex是值得的, 誰用誰知道!

參考

  1. Flex 佈局教程: 語法篇
  2. A Visual Guide to CSS3 Flexbox Properties
  3. A Complete Guide to Flexbox
  4. Getting Dicey With Flexbox: 用flex畫骰子
    flex dice
  5. W3C: CSS Flexible Box Layout Module Level 1
相關文章
相關標籤/搜索