ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[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)