[TOC]
# Flex 布局
2009年,W3C提出了一種新的方案—-**Flex 布局**,可以簡便、完整、響應式地實現各種頁面布局。
Flexbox布局旨在提供一種更有效的途徑,來為容器內子元素進行布局、對齊和分配空間,即便它們的大小是未指定或動態變化的,也能夠很好的適應。
Flexbox布局背后的原理是,賦予父容器更改子元素寬高(或順序)的能力,來更好的填充可用的空間(主要使其適應各種顯示設備和屏幕尺寸)。一個使用Flexbox布局的父容器會伸展每個子元素來填充可用的空間,或者壓縮它們來阻止超出父容器。
**最重要的是**,Flexbox布局在方向上是不可預知的,這一點和常歸布局不同(常規布局中塊是基于豎直方向排列的,而內聯是基于水平方向)。這些常規布局在頁面中顯示都沒問題,但它們缺乏靈活性,難以支撐大型復雜應用的需求,特別是響應方向、大小、伸展、收縮等這些變化。
**注意**:Flexbox最適合用在組件和小規模的布局中,如果是更復雜的布局,Grid布局會比較好一些。
現在[最低的兼容方案](https://css-tricks.com/using-flexbox/):
* Chrome any
* Firefox any
* Safari any
* Opera 12.1+
* IE 10+
* iOS any
* Android any
目前,它已經得到了所有瀏覽器的支持,這意味著,現在就能很安全地使用這項功能。(但是依然不是主流的布局方式,移動web端可以完美使用)
## 基本要素
Flexbox是一個完整的模塊,它不單單是一個屬性,而是包含了一整套新的屬性集,所以這里面涉及到了很多新東西。這些屬性中一些是用來設置父元素(稱為“伸縮容器”)的,而另外一些是設置子元素(稱為“伸縮項目”)的。
**常規布局**是基于塊和內聯流方向(塊就是從上到下,內聯就從左到右),而**Flex布局**是基于flex-flow流。這張圖,解釋了flex布局的主要思想。

基本上,伸縮項目是沿著主軸(main axis),從主軸起點(main-start)到主軸終點(main-end)或者沿著側軸(cross axis),從側軸起點(cross-start)到側軸終點(cross-end)排列。
## 軸

**軸** 包括 `主軸` 和 `交叉軸`,我們知道 `justify-content` 屬性決定子容器沿主軸的排列方式,`align-items` 屬性決定子容器沿著交叉軸的排列方式。
### flex-direction 屬性
**在 flex 布局中,`flex-direction` 屬性決定主軸的方向,交叉軸的方向由主軸確定**。
(主軸的方向不一定是水平的,這個屬性就是設置主軸的方向,主軸默認是水平方向,從左至右,如果主軸方向設置完畢,那么交叉軸就不需要設置,交叉軸永遠是主軸順時針旋轉 90°)。
```css
.ele {
flex-direction: row; // 默認值,主軸為水平方向,起點在左端。
flex-direction: row-reverse; // 主軸為水平方向,起點在右端。
flex-direction: column; // 主軸為垂直方向,起點在上。
flex-direction: column-reverse; // 主軸為垂直方向,起點在下。
}
```
### 主軸與交叉軸
主軸沿逆時針方向旋轉 90° 就得到了交叉軸,主軸與交叉軸的起始端和末尾段由 `flex-start` 和 `flex-end` 表示。
### 注意
討論`justify-content`屬性跟`align-items`屬性的時候,我沒有直接說`justify-content`是flex items在橫軸方向的對齊方式,而是在main axis方向的對齊方向,也沒有說`align-items`是flex items在縱軸方向的對齊方式(或`align-content`是對多行元素在縱軸方向的對齊方式),同樣也是說是在cross axis方向的對齊方式。
**這是因為當`flex-direction`是`row`的時候,main axis是橫向的,而當該值為`cloumn`的時候,main axis則是縱向的。**
所以`justify-content`、`align-items`以及`align-content`屬性對flex items對齊方式的也同樣受`flex-direction`值的影響。
## Flex容器(伸縮項目的父元素)
在使用flexbox彈性布局的時候,首要的就是設置此屬性:
```css
.container{
display: flex; /*or inline-flex*/
}
```
| 屬性名 | 值 |
|---|:---:|:--:|
| `display` | `flex | inline-flex;` |
| `flex-direction` | `row | row-reverse | column | column-reverse` |
| `flex-wrap` | `nowrap | wrap | wrap-reverse` |
| `flex-flow` | `<‘flex-direction’> || <‘flex-wrap’>` |
| `justify-content` | `flex-start | flex-end | center | space-between | space-around` |
| `align-items` | `flex-start | flex-end | center | baseline | stretch` |
| `align-content` | `flex-start | flex-end | center | space-between | space-around | stretch` |
## Flex項(伸縮容器的子元素)
| 屬性名 | 值 |
|---|:---:|:--:|
| `order` | `<integer>` |
| `flex-grow` | `<number> (默認值為: 0)` |
| `flex-shrink` | `<number> (默認值為: 1)` |
| `flex-basis` | `<length> | auto (默認值為: auto) ` |
| `flex` | `none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]` |
| `align-self` | `auto | flex-start | flex-end | center | baseline | stretch` |
## 小結
容器具有這樣的特點:父容器可以統一設置子容器的排列方式,子容器也可以單獨設置自身的排列方式,如果兩者同時設置,以子容器的設置為準。
# `flex:1`簡寫表達
`flex` 默認值是 `0 1 auto`,是`flex-grow`、`flex-shrink`、`flex-basis`的縮寫:
~~~
.item {flex: 2333 3222 234px;}
.item {
flex-grow: 2333;
flex-shrink: 3222;
flex-basis: 234px;
}
~~~
示例:
```
/* From: https://getuikit.com/docs/flex */
/* Item dimensions
========================================================================== */
/*
* Initial: 0 1 auto
* Content dimensions, but shrinks
(內容維度,可以縮小)
*/
/*
* No Flex: 0 0 auto
* Content dimensions
(內容維度)
*/
.uk-flex-none { flex: none; }
/*
* Relative Flex: 1 1 auto
* Space is allocated considering content
(根據內容分配空間)
*/
.uk-flex-auto { flex: auto; }
/*
* Absolute Flex: 1 1 0%
* Space is allocated solely based on flex
(空間是完全基于flex分配的)
*/
.uk-flex-1 { flex: 1; }
```
**number( a non-negative number that serves as a proportion 一個用作比例的非負數)**
## 單值語法
?值必須是如下之一:
* 數值?number(非負數字),被解釋為`flex: number 1 0%`
* 一個能夠描述寬度的值,例如?10em、30%、min-content,被解釋為`flex:1 1 width`
* none:`0 0 auto`
它根據 `width` 和 `height` 來調節元素大小,但是完全不靈活。
```css
.item {flex: none;}
.item {
flex-grow: 0;
flex-shrink: 0;
flex-basis: auto;
}
```
* auto:`1 1 auto`
* initial:
等同于`flex: 0 auto`,也是 `flex: 0 1 auto` 的簡寫表達。伸縮項目不會隨著其伸縮容器的擴展而增長。當其伸縮容器收縮時,它將與其他伸縮項目成比例收縮。
## 雙值語法
雙值語法格式要求如下:
* 第一個值必須是?number,被解釋為?`flex-grow`?屬性
* 第二個值必須是如下之一:
* 數值?number,被解釋為?`flex-shrink`?屬性,計算為`flex:number number 0%`
* 一個能夠描述寬度的值,例如?10em、30%、min-content,被解釋為?`flex-basis`?屬性,計算為`flex:number 1 width`
## 三值語法
* 第一個?number?表示`flex-grow`
* 第二個?number?表示`flex-shrink`
* 第三個描述寬度的值表示`flex-basis`
(Xee 記憶法:GSB(斯坦福商學研究生院(Stanford Graduate School of Business)))
# `flex-basis`
flex-basis 規定的是子元素的基準值。所以是否溢出的計算與此屬性息息相關。
`flex-basis` 規定的范圍取決于 `box-sizing`。這里主要討論以下` flex-basis` 的取值情況:
* auto:檢索伸縮項目(flex item)的主軸大小屬性的值。如果主軸是水平的,主尺寸屬性將是伸縮項目的寬度;如果主軸是垂直的,那么主大小屬性就是伸縮項目的高度。
* content:指示根據伸縮項目內容自動調整大小。避免使用這個關鍵字,因為它還沒有得到很好的支持,等效的替代方案是 `flex-basis` 和主尺寸都取`auto`。
* `<width>`:使用與 css`width`屬性相同的單位解析(px、百分比、em等)。(Xee:**百分比**可是根據其包含塊(即伸縮父容器)的主尺寸計算的!!!)
> Flex Basis 與CSS盒子模型 Width 屬性的區別在哪?
> **content –> width –> flex-basis (limted by max|min-width)**
> 也就是說:
> * 如果沒有設置`flex-basis`屬性,那么`flex-basis`的大小就是項目的`width`屬性的大小
> * 如果沒有設置`width`屬性,那么`flex-basis`的大小就是項目內容(content)的大小
> [`Flex Basis`與`Width`的區別](https://www.jianshu.com/p/17b1b445ecd4)
# 小結
如下的案例,你應該一眼就可以明了:
```
<style>
.container-flex{
display: flex;
background-color: #ccc;
width: 600px;
}
.item{
height: 80px;
line-height: 80px;
width: 200px;
font-size: 2em;
text-align: center
}
.color1{
background-color: #ffadd3;
}
.color2{
background-color: #3aadda;
}
.color3{
background-color: #eeaaa3;
}
.color4{
background-color: #afbda3;
}
</style>
<div class="container container-flex">
<span class="item color1" style="flex: 0 0 auto;">1</span >
<span class="item color2" style="flex: 1 1 auto;">2</span >
<span class="item color3" style="flex: 0 2 auto;">3</span >
<span class="item color4" style="flex: 2 0 auto;">4</span >
</div>
```
你可以在任何在線運行的環境中測試:
https://jsbin.com/
https://codepan.net/
??下圖對應了常見的三種情況:

先確定伸縮項的基準值`flex-basis` 都是 auto,這時取`width: 200px;
`,子元素的總基準值為:`800px`:
1. 如果父容器為`width:800px` 正好適應了所有子元素,所以沒有一個子盒子需要擴大或縮小。
2. 父容器為`width:600px` 不能很好地容納所有子元素,使得設置了`flex-shrink`的子盒子需要按規則縮小。
2. 父容器為`width:1200px` 能容納所有子元素,還有多余空間,會讓設置了`flex-grow`的子盒子按規則擴大。
我們會發現 編號為 1的伸縮項目 始終沒有變化!
> [flex 的默認值是 0 1 auto](https://segmentfault.com/q/1010000004080910)
# Flexbox 解決方案
philipwalton:
* https://github.com/philipwalton/solved-by-flexbox
相反,它的目的是展示曾經很困難甚至無法單獨使用 CSS 能解決的問題,而現在使用Flexbox簡單易用。隨著最近發布的Internet Explorer 11和Safari 6.1,最新的Flexbox規格已經被每一個的現代瀏覽器支持(愚人碼頭注:瀏覽器的支持請客,你可以看 http://caniuse.com/#feat=flexbox)。
* https://github.com/philipwalton/flexbugs
* [使用Flexbox碰到了什么樣的坑?](https://www.zhihu.com/question/29924791)
通過Autoprefixer 來進行前綴修飾。
webkit內核的瀏覽器,必須加上weibkit前綴
```css
.box{
display: -webkit-flex; /* Safari */
display: flex;
}
```
# 需要注意的Flexbox特性
## 無效屬性:
* CSS的`columns`在**伸縮容器**上沒有效果。
* `float`、`clear`和`vertical-align`在**伸縮項目**上沒有效果。
* `::first-line` 和 `::first-letter` 在**伸縮容器**無效
## 伸縮容器中的非空字符文本節點也是伸縮項目

## margin折疊
* 伸縮容器和伸縮項目的`margin`不會折疊
* 伸縮項目間的`margin`不會折疊
## 舊版Flexbox的BUG
伸縮項目為行內元素時,要加`display:block;`或`display:flex`
# Flexbox playground
這里是一個靈活的運動場,您可以在其中演示不同的Flex屬性,并探索Flexbox布局的強大功能。組合幾個flex屬性以獲得復雜的布局。
See the Pen [Flexbox Properties Demonstration](https://codepen.io/justd/pen/yydezN/) by Dimitar (@[justd](https://codepen.io/justd/)) on CodePen.
您也可以在[這里查看](https://scotch.io/demos/visual-guide-to-css3-flexbox-flexbox-playground)完整頁面,或者在GitHub[獲取源代碼](https://github.com/imjustd/flexbox-playground)。
如果你想在你的項目中使用 Flexbox 之前進行更多地嘗試,您可以訪問 [Flexyboxes](http://the-echoplex.net/flexyboxes/) 和 [Flexbox Froggy](http://flexboxfroggy.com/) 練習。你也可以閱讀 [CSS trick: Flexbox 指南](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) 和 [W3C:CSS Flexible Box](https://drafts.csswg.org/css-flexbox/)。
# [CSS3 Flexbox Reference](http://dundalek.com/css3-flexbox-reference/)
這是對CSS靈活的框布局模塊屬性的快速參考和概述。
# 實用案例
https://codepen.io/HugoGiraudel/pen/qIAwr
可以看下這篇國外的文章:[Using Flexbox today](http://chriswrightdesign.com/experiments/using-flexbox-today/)
# flex-start 和 baseline 之間有什么區別?
http://www.it1352.com/563082.html
# 問題?
1. **`white-space`對 flex 彈性布局有影響**。在網上找了一系列的資料,找到一個解決辦法,給使用了`white-space`的**子標簽添加一個屬性`min-width: 0`**,可以解決問題。
2. [flex布局最后一行左對齊的處理](https://www.cnblogs.com/yankfy/p/flexleft.html)
[讓CSS flex布局最后一行左對齊的N種方法](https://mp.weixin.qq.com/s/RgRd31ViXpcEpwmnpRxqVA)
3. Flex 如何讓最后一項右邊對齊?
https://blog.csdn.net/henryhu712/article/details/82427806
# 參考
> [Understanding Flexbox: Everything you need to know](https://medium.freecodecamp.org/understanding-flexbox-everything-you-need-to-know-b4013d4dc9af)
[徹底理解Flexbox](https://blog.csdn.net/liuhe688/article/details/51453330)
> [大漠](http://www.w3cplus.com/css3/a-guide-to-flexbox.html)
> https://juejin.im/post/58e3a5a0a0bb9f0069fc16bb
> [CSS 彈性盒子布局](https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Flexible_Box_Layout)
> https://segmentfault.com/a/1190000009932882
> http://www.oxxostudio.tw/articles/201501/css-flexbox.html
> [flex布局詳解](https://github.com/laizimo/zimo-article/issues/13)
- 必備基礎
- 基礎知識
- BFC
- 層疊上下文 Stacking Context
- 視覺格式化模型 Visual formatting model
- CSS3中使用HSL顏色指南
- z-index
- line-height
- vertical-align 屬性
- 垂直居中
- overflow
- CSS3 Gradients
- CSS3 動畫基礎
- 難點知識
- 布局篇
- Flex布局
- =====
- Grid布局
- 多列布局
- 高級布局
- 預編譯器篇
- PostCSS
- Sass
- stylus
- 模塊篇
- 良好的使用
- CSS 模塊化
- 技巧篇
- 未來的CSS
- 動畫篇
- 工具篇
- CSS架構
- CSS 命名方法論
- BEM
- CSS解釋器
- 常用框架
- 參考
- 唰唰聲