你的位置:首页 > 网页设计

[网页设计]译文:Flexbox 完全指南 (A Complete Guide to Flexbox)

  • 原文:A Complete Guide to Flexbox
  • 作者:Chris Coyier
  • 原文最后更新:July 20, 2017
  • 译者:leotso

 

背景

Flexbox 布局 (Flexible Box) 模块 (目前是 W3C 的一个最后征集工作草案(Last Call Working Draft))旨在提供一种更有效的方式,在容器的项之间处理布局、对齐和空间分配,即使它们的大小未知并且/或是动态变化的(因此叫做“flex”)。

Flex 布局背后的主要思想是让容器能够改变其项的宽度/高度(和顺序),以最好地填充可用空间(主要是为了适应各种显示设备和屏幕大小)。一个 flex 容器扩大其项来填充可用的空闲空间,或者缩小它们以防止溢出。

最重要的是,flexbox 布局与常规布局(基于垂直的块(block)、基于水平的内联(inline))截然相反,flexbox 布局是方向无关的。虽然常规布局工作很适合页面,但它们缺乏灵活性(没有双关语)来支持大型或复杂的应用程序(特别是当涉及到方向变化、大小调整、拉伸、收缩等)时。

注意:Flexbox 布局最适合应用程序的组件和小型布局,而网格布局则适合更大规模的布局。

 

基础和术语

由于 flexbox 是一个完整的模块,而不是一个单独的属性,它涉及到很多东西,包括它的全部属性。其中一些是要在容器上设置的(父元素,称为“flex容器”),而其他的则是设置在子元素上(称为“flex项/元素”)。如果常规布局是基于块(block)和内联(inline)流方向,那么 flex 布局则基于“flex流方向(flex-flow direction)”。 请看一看规范中的下图,其解释了 flex 布局背后的主要思想。

 基本上,弹性项(flex items)将沿着主轴(main axis)(从 main-start 到 main-end)或侧轴(cross axis)(从 cross-start 到 cross-end)布局。

  • main axis - flex容器的主轴是主要的轴,flex项被沿其放置。当心,它不一定是水平的;这取决于 flex-direction 属性的值(见下)。
  • main-start | main-end - flex 项放在容器内,从 main-start 到 main-end。
  • main size - 一个弹性项的宽度或高度,任何一个在主维度上,就是这个项的主尺寸。flex 项的 main size 属性是“宽度”或“高度”属性之一,任何一个都可以是 main size。
  • cross axis - 垂直于主轴的轴称为横轴。它的方向取决于主轴方向。
  • cross-start | cross-end - Flex行充满了flex项,并将其放置到容器中,行开始于Flex容器的 cross-start 端,并向 cross-end 端方向前进。
  • cross size - 一个 flex 项的宽度或高度,任何一个在侧维度上,就是该项的 cross size。cross size属性是在侧维度上的“宽度”或“高度”中其一。

Properties for the Parent

(flex container)

Properties for the Children

(flex items)

 

# display

定义一个 flex 容器;inline 或 block 取决于给定的值。它为所有直接的子元素提供一个 flex 上下文。    .container {        display: flex; /* or inline-flex */    }注意,CSS 列对 flex 容器没有影响。 

# flex-direction

确定主轴, 用来定义 flex 容器中的 flex 项的放置方向。Flexbox 是(除了可选的 wrap)一个单向布局概念。可以将 flex 项看作主要是在水平的行或垂直的列中布局的。    .container {        flex-direction: row | row-reverse | column | column-reverse;    } 
  • row (default): 从左到右(如果元素的 dir 属性为 ltr);从右到左(如果元素的 dir 属性为 rtl)
  • row-reverse: 从右到左(如果元素的 dir 属性为 ltr);从左到右(如果元素的 dir 属性为 rtl)
  • column: 自上而下
  • column-reverse: 自下而上

# flex-wrap

默认情况下,flex 项都将尝试放置在一行上。你可以根据需要使用该属性来更改默认行为以支持换行。    .container{        flex-wrap: nowrap | wrap | wrap-reverse;    } 
  • nowrap (default): 所有 flex 项位于一行中
  • wrap: flex 项将从上到下多行排列
  • wrap-reverse: flex 项将从下到上多行排列
这里有一些 flex-wrap 的可视化演示。 

# flex-flow (适用于:父 flex 容器元素)

这是一个简化的 flex-direction 和 flex-wrap 属性,它们一起定义了 flex 容器的主和侧轴。默认是 row nowrap。    flex-flow: <‘flex-direction’> || <‘flex-wrap’> 

# justify-content

该属性定义了浏览器如何分配顺着父容器主轴的弹性元素之间及其周围的空间。它帮助分配剩余的空闲空间当无论在一行中的所有 flex 项是固定大小的还是弹性的但是达到它们的最大尺寸的时候。 当它们溢出行时,该属性也能这些项的对齐方式发挥一些控制作用。     .container {        justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;    } 
  • flex-start (default): 从行首开始排列。每行第一个弹性元素与行首对齐,同时所有后续的弹性元素与前一个对齐
  • flex-end: 从行尾开始排列。每行最后一个弹性元素与行尾对齐,其他元素将与后一个对齐
  • center: 伸缩元素向每行中点排列。每行第一个元素到行首的距离将与每行最后一个元素到行尾的距离相同
  • space-between: 在每行上均匀分配元素;第一个元素位于行首,最后一个元素位于行尾
  • space-around: 元素在行内均匀分布,在元素周围的间距相等。注意,视觉上的间距不相等,因为所有元素在其两边都有相等的空白。第一个元素距离容器边缘有一个单位的空白,而元素之间有两个单位的空白因为下一个元素也有其自己的空白边距。
  • space-evenly: 元素到容器边缘及元素之间间距相等地均匀分布方式。
 

# align-items

该属性定义弹性元素沿当前行的侧轴方向上如何布局的默认行为。可以将其理解为 justify-content 应用于侧轴的版本(垂直于主轴)。    .container {        align-items: flex-start | flex-end | center | baseline | stretch;    } 
  • flex-start: 元素侧轴起点的边缘与行的侧轴起点对齐
  • flex-end: 元素侧轴终点的边缘与行的侧轴终点对齐
  • center: 元素在侧轴方向上居中对齐
  • baseline: 所有元素向基线对齐。侧轴起点到元素基线距离最大的元素将会于侧轴起点对齐以确定基线
  • stretch (default): 弹性元素被在侧轴方向被拉伸到与容器相同的高度或宽度。(同时遵守 min-width/max-width 属性的设置

# align-content

该属性设置当在侧轴方向上有额外空间的时候弹性容器中行的对齐方式,类似于在主轴上 justify-content 属性对个体元素的对齐方式。注意:该属性在弹性容器中仅有一行弹性元素的情况下没有效果。    .container {        align-content: flex-start | flex-end | center | space-between | space-around | stretch;    } 
  • flex-start: 所有行从侧轴起点开始填充。第一行的侧轴起点边和容器的侧轴起点边对齐。接下来的每一行紧跟前一行
  • flex-end: 所有行从侧轴末尾开始填充。最后一行的侧轴终点和容器的侧轴终点对齐。同时所有后续行与前一个对齐
  • center: 所有行朝向容器的中心填充。每行互相紧挨,相对于容器居中对齐。容器的侧轴起点边和第一行的距离相等于容器的侧轴终点边和最后一行的距离
  • space-between: 所有行在容器中平均分布。相邻两行间距相等。容器的侧轴起点边和终点边分别与第一行和最后一行的边对齐
  • space-around: 所有行在容器中平均分布,相邻两行间距相等。容器的侧轴起点边和终点边分别与第一行和最后一行的距离是相邻两行间距的一半
  • stretch (default): 拉伸所有行来填满剩余空间。剩余空间平均的分配给每一行
 

# order

默认情况下,flex 元素按源顺序排列。同时,order 属性可以控制它们在弹性容器中出现的顺序。    .item {        order: <integer>;    } 

# flex-grow

该属性定义弹性盒子项(flex item)的拉伸因子,它定义了一个 flex 项在必要时可以拉伸的能力。它接受一个无单位数值,作为一个比例。它规定了 flex 项在 flex 容器内可占据的可用空间的大小。如果所有项的 flex-grow 属性都设置为 1,那么容器中的剩余空间将平均分配给所有的子元素。如果其中一个子元素的值为 2,那么其对剩余空间的占用将比其他项多一倍(或者至少尝试一下)。    .item {        flex-grow: <number>; /* default 0 */    }负值是无效的。 

# flex-shrink

这定义了一个 flex 项在必要时收缩的能力。flex 元素仅在默认宽度之和大于容器的时候才会发生收缩,其收缩的大小是依据 flex-shrink 的值。    .item {        flex-shrink: <number>; /* default 1 */    }负值是无效的。 

# flex-basis

这定义了在剩余空间被分配之前,元素的默认大小。它可以是一个长度(例如 20%,5rem 等)或一个关键字。auto 关键字的意思是“看我的 width 或 height 属性”(这是由关键字 main-size 临时完成的,直到废弃为止)。content 关键字的意思是“基于项中内容的大小调整尺寸” ———— 这个关键字还没有得到很好的支持,所以很难测试,也很难知道它的同胞属性 max-content、min-content 和 fit-content 是什么。    .item {        flex-basis: <length> | auto; /* default auto */    }如果设置为0,则不将内容周围的额外空间考虑在内。如果设置为 auto,额外的空间将基于它的 flex-grow 属性值分配。 查看此图。 

# flex

这是一个简写属性,可以同时设置 flex-grow, flex-shrink 与 flex-basis。第二和第三个参数(flex-shrink 和 flex-basis)是可选的。默认为 0 1 auto。    .item {        flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]    }建议使用这个简写属性,而不是设置单个属性。 

# align-self

这允许对单个 flex 元素覆盖默认对齐(或者由 align-item 指定的对齐)。属性值请参考对 align-items 属性的解释。    .item {        align-self: auto | flex-start | flex-end | center | baseline | stretch;    } 注意,float,clear 和 vertical-align 对弹性元素没有影响。

 

Examples

让我们从一个非常简单的例子开始,解决一个几乎日常的问题:完美地居中。如果你使用 flexbox,那就不能再简单了。
.parent { display: flex; height: 300px; /* Or whatever */}.child { width: 100px; /* Or whatever */ height: 100px; /* Or whatever */ margin: auto; /* Magic! */}
这就依赖于在 flex 容器中设置 “auto” 的 margin 吸收额外的空间。因此,设置一个垂直的 margin 为 auto,将使这个 flex 项完美地在两个轴上居中。 现在我们来使用更多的属性。 考虑一个拥有6个元素的 list,所有元素都有一个固定的尺寸,在美学问题上,但它们可以是自动大小的。我们希望它们在水平轴上均匀地分布,这样当我们调整浏览器的大小时,一切都很好(没有 media query!)。
.flex-container { /* We first create a flex layout context */ display: flex;  /* Then we define the flow direction and if we allow the items to wrap  * Remember this is the same as:  * flex-direction: row;  * flex-wrap: wrap;  */ flex-flow: row wrap;  /* Then we define how is distributed the remaining space */ justify-content: space-around;}
完成。其他的都只是一些样式的问题。 下面是本例在 CodePen 上的一个 pen。一定要去CodePen,试着调整你的窗口大小,看看会发生什么。https://codepen.io/team/css-tricks/pen/EKEYob  让我们试试别的。假设我们在我们的网站上有一个右对齐的导航,但我们希望它在中等大小的屏幕上居中对齐,而在小的设备上是单列的。非常简单。
/* Large */.navigation { display: flex; flex-flow: row wrap; /* This aligns items to the end line on main-axis */ justify-content: flex-end;}
/* Medium screens */@media all and (max-width: 800px) { .navigation { /* When on medium sized screens, we center it by evenly distributing empty space around items */ justify-content: space-around; }}
/* Small screens */@media all and (max-width: 500px) { .navigation { /* On small screens, we are no longer using row direction but column */ flex-direction: column; }}
https://codepen.io/team/css-tricks/pen/YqaKYR  让我们利用弹性元素的灵活性来尝试一些更有趣的事情。一个移动优先(mobile-first)的带有全宽(full-width)页头和页脚的三列布局怎么样,并且独立于源顺序。
.wrapper { display: flex; flex-flow: row wrap;}
/* We tell all items to be 100% width */.header, .main, .nav, .aside, .footer { flex: 1 100%;}
/* We rely on source order for mobile-first approach* in this case:* 1. header* 2. nav* 3. main* 4. aside* 5. footer*//* Medium screens */@media all and (min-width: 600px) { /* We tell both sidebars to share a row */ .aside { flex: 1 auto; }}
/* Large screens */@media all and (min-width: 800px) { /* We invert order of first sidebar and main * And tell the main element to take twice as much width as the other two sidebars */ .main { flex: 2 0px; } .aside-1 { order: 1; } .main { order: 2; } .aside-2 { order: 3; } .footer { order: 4; }}

https://codepen.io/team/css-tricks/pen/jqzNZq

 

Flexbox 前缀

Flexbox 需要一些供应商(vendor)的前缀来支持尽可能多的浏览器。它不仅包含带有供应商前缀的前置修饰属性,还包括实际上完全不同的属性和值名。这是因为 Flexbox 规范已经随着时间的推移而改变,创建了一个“旧的”、“过渡的”和“新的”版本。也许处理这一问题的最好方法是编写新的(和最终的)语法,并通过 Autoprefixer 运行您的CSS,它能够很好地处理回退问题。或者,这里有一个 Sass 的 @mixin 来帮助处理一些前缀,这也让你知道需要做些什么:
@mixin flexbox() { display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;}@mixin flex($values) { -webkit-box-flex: $values; -moz-box-flex: $values; -webkit-flex: $values; -ms-flex: $values; flex: $values;}@mixin order($val) { -webkit-box-ordinal-group: $val; -moz-box-ordinal-group: $val; -ms-flex-order: $val; -webkit-order: $val; order: $val;}.wrapper { @include flexbox();}.item { @include flex(1 200px); @include order(2);}

 

相关文章

  • A Complete Guide to Grid
  • Almanac entries on Grid properties, like grid-row / grid-column

其他资源

  • Flexbox in the CSS specifications
  • Flexbox at MDN
  • Flexbox at Opera
  • Diving into Flexbox by Bocoup
  • Mixing syntaxes for best browser support on CSS-Tricks
  • Flexbox by Raphael Goetter (FR)
  • Flexplorer by Bennett Feely

Bugs

Flexbox 当然不是没有它的 bug/缺陷/issue。我目前所看到的最好的关于它们的收集是 Philip Walton 和 Greg Whitworth 的 Flexbugs。这是一个用来追踪所有 bug/缺陷/issue 的开放源代码的地方,所以我认为最好只是将它链接在此。 

浏览器支持

根据 flexbox 的“版本”拆分:
  • (new) 表示规范中最新的语法(例如 display: flex;)
  • (tweener) 这是2011年以来的一种怪异的非官方语法(例如 display: flexbox;)
  • (old) 表示从2009开始的旧的语法(例如 display: box;)
ChromeSafariFirefoxOperaIEAndroidiOS
20- (old)3.1+ (old)2-21 (old)12.1+ (new)10 (tweener)2.1+ (old)3.2+ (old)
21+ (new)6.1+ (new)22+ (new)11+ (new)4.4+ (new)7.1+ (new)
 有关如何混合语法以获得最佳浏览器支持的更多信息,请参考 this article (CSS-Tricks) 或者 this article (DevOpera)。黑莓浏览器 10+ 支持新语法。