[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布局的主要思想。
![Flex布局](https://box.kancloud.cn/dac8dfea115cc9010991bedbaa2822e2_554x320.png)
基本上,伸缩项目是沿着主轴(main axis),从主轴起点(main-start)到主轴终点(main-end)或者沿着侧轴(cross axis),从侧轴起点(cross-start)到侧轴终点(cross-end)排列。
## 轴
![](https://box.kancloud.cn/de8487ab0f87ce2c2704ec4c71bd6dd5_850x280.png)
**轴** 包括 `主轴` 和 `交叉轴`,我们知道 `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/
👇下图对应了常见的三种情况:
![多种情况](https://img.kancloud.cn/08/33/0833dde31310e0038457c41d67ef6fad_470x272.png)
先确定伸缩项的基准值`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` 在**伸缩容器**无效
## 伸缩容器中的非空字符文本节点也是伸缩项目
![](https://box.kancloud.cn/9f2444dabdc92e202dc4383d19bfd799_320x60.png)
## 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解释器
- 常用框架
- 参考
- 唰唰声