Flexbox 佈局入門

互聯網早期實現佈局是須要經過多種不一樣屬性組合才能實現咱們想要的佈局。css

好比常見的垂直居中,剛接觸 css 的朋友看到 vertical-align: middle; 這個屬性可能就會認爲它就是用於垂直居中的,但實際上並無那麼簡單。若是想要經過該屬性來實現垂直居中,還須要其餘小夥伴配合。html

.container {
  width: 200px;
  height: 200px;
  border-radius: 6px;
  text-align: center;
  color: #fff;
  background: #e44b27;
  white-space: nowrap;
}

/* 該僞類是實現垂直居中關鍵 */
.container:after {
  content: '';
  display: inline-block;
  height: 100%;
  vertical-align: middle;
}
.content {
  display: inline-block;
  white-space: normal;
  vertical-align: middle;
  text-align: left;
}
<div class="container">
  <div class="content">我想居中!</div>
</div>

這樣看來,爲了實現垂直居中佈局,咱們還得打一套組合拳才能出來才行,是否是看起來有點麻煩的樣子?前端

W3C 在 2009 年提出的 Fiexbox(flex) 佈局草案,就是針對用戶界面設計優化的 CSS 盒模型。若是使用 flex 佈局來實現上面的垂直居中佈局的話,能夠簡化爲:java

.container {
  width: 200px;
  height: 200px;
  border-radius: 6px;
  color: #fff;
  background: #e44b27;

  /* 使用 flex 佈局 */
  display: flex;
  justify-content: center;
  align-items: center;
}
<div class="container">
  <div>我想居中!</div>
</div>

修改後的代碼就顯得更精簡了,也不須要其餘小夥伴來搭把手。佈局的事情就讓 flex 家族本身來解決便可。ios


概念

應用 flex 佈局的容器咱們一般稱爲 彈性盒子/容器(flex container)。彈性容器能夠由 display: flexdisplay: inline-flex 生成。彈性盒子的子項常稱爲 彈性元素/項目(flex items),它以 flex 佈局模型進行佈局。css3

.container {
  display: flex | inline-flex;
}

若是想要學習 flex 佈局的工做方式,最早須要學習的是它自身的術語。下面直接引用 flex 草案中術語的介紹圖:git

別被原版英文術語給嚇倒了,我們翻譯一下其實就很好理解了:github

在術語示意圖中能夠看到兩根軸,分別是主軸(main axis)垂直交叉軸(cross axis)。同時標註了主軸起點(main start)終點(main end)交叉軸的起點(cross start)終點(cross end)web

默認狀況下 flex 佈局是按主軸的方向進行佈局的。flex 元素所佔據的 主軸空間(main size) 就是 flex 元素的寬度(width)、所佔據的 交叉軸空間(cross size) 就是 flex 元素的高度(height)。chrome


flex 容器屬性

flex 容器裏能夠經過如下幾種屬性來控制容器的行爲:

  • flex-direction
  • flex-wrap
  • flex-flow
  • justify-content
  • align-content
  • align-items

爲了更好的觀察各屬性的行爲,筆者在 codepen 上給不一樣屬性都寫了 demo 作參考。

目前有個新規範(CSS Box Alignment Module Level 3)正處於工做草案的狀態中,對一些屬性添加新值,如 [first|last]? baselineself-startself-endstartendleftrightunsafe | safe

這些新值多數瀏覽器都沒實現,爲了便於演示,此處僅講解初始版本的值。Firefox 瀏覽器對新值實現的比較超前,也建議經過使用 Firefox 瀏覽器來查看 demo。

flex-direction

flex-direction 指示內部元素如何在 flex 容器中佈局。能夠簡單的理解爲 flex 容器的佈局方向。其默認值爲 row,可選語法以下:

/* 經常使用屬性 */
flex-direction: row | row-reverse | column | column-reverse;
  • row: 主軸起點和主軸終點與內容方向相同。簡而言之就是內容從左到右進行佈局。
  • row-reverse: 與 row 行爲相同,但主軸起點和主軸終點對調了位置。
  • column: 主軸由水平方向轉爲垂直方向,佈局從上往下排。
  • column-reverse: 主軸由水平方向轉爲垂直方向,佈局從上往下排。

值得注意的是,全局屬性 dir 的做用是指示元素的文本的方向性,該屬性會受到 rowrow-reverse 的影響。

本例 codepen demo: flex-direction

flex-wrap

flex-wrap 指定 flex 元素單行顯示仍是多行顯示 。若是能夠換行,你甚至還能夠經過該屬性控制行的堆疊方向。它的取值以下所示:

flex-wrap: nowrap(默認值) | wrap | wrap-reverse;

能夠經過本例 demo 右上角的按鈕來修改元素的數量,觀察三個值之間的變化:

  • nowrap: flex 容器寧願壓榨元素的空間也不願換行。甚至壓縮到必定地步後還會溢出容器。
  • wrap: 若子項超過容器所容納的寬度,則容許斷行展現。
  • wrap-reverse: 和 wrap 的行爲同樣,只是交叉軸起點與終點互換

本例 codepen demo: flex-wrap

flex-flow

flex-flow 屬性是 flex-directionflex-wrap 的簡寫。這個沒啥好說的,也就不額外寫 demo 了。

/* 語法 */
flex-flow: <flex-direction> || <flex-wrap>;

/* 單獨設置 flex-direction 的屬性 */
flex-flow: row;
flex-flow: column;

/* 單獨設置 flex-wrap 的屬性 */
flex-flow: nowrap;
flex-flow: wrap;

/* 同時設置兩種屬性,建議按照語法順序進行書寫 */
flex-flow: row nowrap;
flex-flow: column wrap;

justify-content

justify-content 屬性定義了容器主軸中各 flex 元素之間的對齊方式。這是 flex 佈局中經常使用的屬性之一。

justify-content: normal |
                 space-between | space-around | space-evenly |
                 center | flex-start | flex-end

在初始版本中,justify-content 的默認值爲 flex-start。但在最新版本中的 chrome 瀏覽器被修改成了 normal

爲了對比屬性之間的差別,本例 demo 將元素的兩側 margin 清空:

  • normal: 排列效果等同 flex-start
  • flex-start: 默認狀況是左對齊,從行首開始排列。每行第一個 flex 元素與行首對齊,同時全部後續的 flex 元素與前一個對齊。
  • flex-end: 默認狀況下是右對齊,從行尾開始排列。每行最後一個 flex 元素與行尾對齊,其餘元素將與後一個對齊。
  • center: 該值使元素居中對齊。

  • space-between: 首尾兩端對齊,內部元素之間的間距相等。
  • space-around: 在每行上均勻分配彈性元素。相鄰元素間距離相同,首尾兩個元素的距離是相鄰元素之間距離的一半
  • space-evenly: 主軸內各元素兩側均勻分配剩餘空間。(注意此處與 space-around 的差別)

本例 codepen demo: justify-content

align-items

align-items 屬性除了能夠在 flex 佈局中有效,還能夠在 grid(網格) 佈局中應用。在 flex 佈局中它的做用是決定交叉軸的對齊方式。這也是 flex

/* 主流瀏覽器已經實現的值 */
align-items: normal | flex-start | flex-end | center | baseline | stretch

/* 新草案添加的值 */
align-items:  | start | end | [ first | last ]baseline | left | right

  • normal: 在 flex 佈局中 normal 的表現效果如同 stretch 同樣。
  • stretch: 彈性元素被在交叉軸軸方向被拉伸到與容器相同的高度或寬度。若容器沒有設置高度,則取當前行中最高元素的高度,如本例中元素 4 是第一行中最高的元素,那第一行中的高度都被拉伸到與最高元素相同的高度。第二行中最高的元素是元素 2,所以第二行高度都取至元素 2。

  • flex-start: 元素向交叉軸起點對齊。
  • flex-end: 元素向交叉軸終點對齊。
  • center: 元素在交叉軸居中。

  • baseline: 全部元素向基線對齊。側軸起點到元素基線距離最大的元素將會於側軸起點對齊以肯定基線。在例子中放大元素 6 的 font-size, 與 center 進行對比就能看到差別了。

本例 codepen demo: align-items

align-content

justify-content 是做用於主軸上,而 align-content 則是用於定義交叉軸的對齊方式。值得注意的是,若 flex 容器內只有一根軸線,該屬性將不起做用

/* 主流瀏覽器已經實現的值 */
align-content: normal | space-between | space-around | space-evenly | stretch |  center | flex-start | flex-end

/* 主流瀏覽器多數未實現的值 */
align-content: [first|last]? baseline, start, end, left, right

父容器設置了 flex 佈局後,若子元素沒有設定 height 屬性的話,默認會將容器內的子元素進行拉伸。

爲了便於觀察二者的差別,筆者在 demo 中新增一列進行對比。左列的 flex 元素使用 height 屬性,右列使用 min-height 屬性。同時將 flex 容器高度設置爲 400px:

  • normal: 像未設置值,元素處於默認位置。
  • stretch: 拉伸全部行來填滿剩餘空間。剩餘空間平均的分配給每一行(若某元素設置了高度,那麼該值對這個元素將不會起做用)。

  • flex-start: 交叉軸起點對齊。
  • flex-end: 交叉軸終點對齊。
  • center: 交叉軸居中對齊。

  • space-between: 交叉軸兩端對齊,行之間間距相等
  • space-around: 交叉軸均勻對齊,行兩端間距相等
  • space-evenly: 交叉軸內各元素兩側均勻分配剩餘空間。

本例 codepen demo: align-content


Flex Item

Flex Container(彈性容器)的一級子元素就是 Flex item(彈性元素)。如下主要應用於 Flex item 的屬性。

  • flex-basis
  • flex-grow
  • flex-shrink
  • flex
  • align-self
  • order

flex-grow

flex-grow 屬性用於定義元素所佔有的比例,它接受一個正整數,默認值爲 0

flex-grow: <number>

/* 例子: 僅接受正數的值 */
flex-grow: 1;

flex-grow.jpg

本例 codepen demo: align-content

flex-shrink

flex-grow 相反,flex-shrink 屬性處理元素收縮的問題,默認爲 1,意味着元素默認會隨着容器縮小而等比例縮小。當值爲 0 時則不縮放。

flex-shrink: <number>

/* 例子: 默認縮放 */
flex-shrink: 1;

/* 例子: 使元素不縮放 */
flex-shrink: 0;

在如下 demo 中,各 flex 項目的寬高相等。當父容器有足夠的空間時,元素不須要緊衣縮食,所以 flex-shrink 也沒有機會表現出它的做用。

將 flex 容器尺寸調小後能夠發現,flex-shrink 的值越大,元素被壓榨的空間越多。

本例 dmeo: flex-shrink

flex-basis

flex-basis 指定了 flex 元素在主軸空間(main size)所佔的初始大小。

flex-basis:  <'width'>

當一個元素同時被設置了 flex-basis (值爲 auto 除外)和 width 屬性時,flex-basis 具備更高的優先級。

W3C 鼓勵使用 flex 簡寫屬性(下一小節進行秒速)來控制靈活性,而不是直接使用 flex-basis 屬性。由於簡寫屬性 flex 能夠正確地重置任何未指定的屬性以適應常見的用途。

本例 demo: flex-basis

flex

flex 屬性是 flex-growflex-shrinkflex-basis 的簡寫,規定了彈性元素如何伸縮以適應 flex 容器中的可用空間,默認值爲 0 1 auto

flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]

flex 屬性能夠指定 1 個,2 個或 3 個值。

單值語法: 值必須爲如下其中之一:

  • 一個無單位數(<number>): 它會被看成 <flex-grow> 的值。
  • 一個有效的寬度(width)值: 它會被看成 <flex-basis>的值。
  • 關鍵字 noneautoinitial

雙值語法: 第一個值必須爲一個無單位數,而且它會被看成 <flex-grow> 的值。第二個值必須爲如下之一:

  • 一個無單位數:它會被看成 <flex-shrink> 的值。
  • 一個有效的寬度值: 它會被看成 <flex-basis> 的值。

三值語法:

  • 第一個值必須爲一個無單位數,而且它會被看成 <flex-grow> 的值。
  • 第二個值必須爲一個無單位數,而且它會被看成 <flex-shrink> 的值。
  • 第三個值必須爲一個有效的寬度值, 而且它會被看成 <flex-basis> 的值。

這個屬性沒啥好演示的,其實就是以前介紹的三個屬性的組合:

本例 demo: flex

align-self

align-self 屬性在 flex 佈局中做用於單個 flex 元素上,它將控制指定元素在交叉軸上的位置。

align-self: auto | normal | stretch | center | flex-start | flex-end;

/* 多數瀏覽器未實現的功能 */
align-self: start | end | self-start | self-end | [first | last]? baseline;
  • auto: 設置爲父元素的 align-items 值,若是該元素沒有父元素的話,就設置爲 stretch
  • normal: 在 flex 佈局中,至關於 stretch 的效果。
  • stretch: flex 元素將會基於容器的寬和高,按照自身 margin box 的 cross-size 拉伸。
  • center: 使項目在交叉軸中居中。
  • flex-start: flex 元素會對齊到 cross-axis 的首端。
  • flex-end: flex 元素會對齊到 cross-axis 的尾端。

本例 demo: align-self

order

order 屬性用於設置指定 flex 元素在容器中的順序。容器中的 flex 元素按升序值排序,若值相同則按其源代碼出現的順序進行排序,默認值爲 0。它接受一個整數值(integer),如 -203 等。

order: <integer>

咱們能夠操做下面的 demo 來控制元素的順序,好比將第三項元素經過 order 在移動到第一位。

本例 demo: order​

兼容性

要將學到的新東西應用到實際項目中就不得不考慮其兼容性了。經過 caniuse 咱們能夠看到:flex 佈局通過多年的發展,主流瀏覽器都已經對 flex 佈局基本模塊都實現完畢了。

PC 端須要考慮的是要不要兼容 IE,移動端最低兼容爲 ios 3.2+、Android 2.1+。若是你須要開發微信小程序,那麼小程序官方就推薦使用 flex 佈局。

早期 flex 佈局是經過 display: box; 來申明,這是使用了舊的規範,後來該值被 flex 給替換掉了。還有一些很低版本的瀏覽器或許還須要添加瀏覽器前綴才能使用 flex 佈局。所以你在某處看到以下代碼也不用感到奇怪,這是開發者在給佈局作兼容呢:

.flex-center {
  display: -webkit-box;
  display: -webkit-flex;
  display: -moz-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
  -webkit-justify-content: center;
     -moz-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
  -webkit-box-align: center;
  -webkit-align-items: center;
     -moz-box-align: center;
      -ms-flex-align: center;
          align-items: center;
}

但若是要咱們在開發時手動寫這種兼容好像不是很靠譜,兼容又冗餘。所幸如今的前端開發都會使用腳手架,這些腳手架通常都會內置 postcss 和 autoprefix 之類的插件來幫助咱們完成這些事。

還有一些朋友可能會說,咱們老項目仍是得要兼容 IE 8+ 呀,是否是意味着跟 flex 佈局無緣了?其實不是的,github 上有一個叫 flexibility 的 polyfill 可讓 IE8 + 也實現 flex 佈局效果.

結束

本篇介紹了 flex 佈局該如何使用、各屬性的做用與效果,下一篇再詳細講講 flex 佈局在實際工做中的妙用~

因爲不支持插入 codepen 和 caniuse,所以將這些外部 demo 都轉爲了圖片。若是想預覽各屬性的效果能夠直接訪問原文: Flexbox 佈局入門 | anran758's blog 進行操做或者直接打開各 demo 所在頁。

參考資料:

  1. CSS Flexible Box Layout Module Level 1
  2. CSS Box Alignment Module Level 3
  3. MDN | Flex Item

目前鴿子羣彙集了前端、java、Python 等不一樣語言的博主,你們大多都有寫博客的習慣。歡迎對 web 領域感興趣,或者有在寫博客的同窗加入談論~

相關文章
相關標籤/搜索