摘要:本文譯自這里,針對本文介紹的屬性列個提綱伸縮容器屬性伸縮項目屬性以后再布局時可以考慮用啦背景布局模塊目前上一次工作草案的叫法旨在提供一種更高效的方式來布局排列及分配容器中項目的空間,即便容器大小是未知或動態變化的因此稱為。
本文譯自 A Complete Guide to Flexbox
這里,針對本文介紹的屬性列個提綱:
伸縮容器屬性:
display
flex-direction
flex-wrap
flex-flow
justify-content
align-items
align-content
伸縮項目屬性:
order
flex-grow
flex-shrink
flex-basis
flex
align-self
以后再布局時可以考慮用flexbox啦~~
背景
Flexbox 布局(Flexible Box)模塊(目前W3C上一次工作草案的叫法)旨在提供一種更高效的方式來布局、排列及分配容器中項目的空間,即便容器大小是未知或動態變化的(因此稱為“flex”)。
Flex布局的主要思想是使容器具備改變其子項目的寬度或高度的能力,以此充分填充可用空間(主要是為了適應各種顯示設備和屏幕尺寸)。使用flex布局的容器能擴展其子項目來填滿可用空間,也能縮小他們以防止溢出容器。
Flex布局與常規布局相比,最主要的是它是方向無關的(常規布局通常是塊級元素從上到下布局,行內元素從左到右布局)。盡管常規布局對于頁面布局十分好用,但卻缺少對大型或復雜應用的靈活性支持(尤其是當涉及到取向改變,尺寸調整,拉伸,收縮等場景時)。
注意:Flexbox布局主要適用于應用的組件以及小規模的布局,對于那些較大規模的布局網格布局更適用。
基本概念&術語
Flexbox是一整個模塊,并非單一的一個屬性,它涉及的東西比較多,包括一系列屬性。其中一些屬性是用在容器(父元素,即伸縮容器)上的,其他一些屬性則是用在子元素(伸縮項目)上的。
如果說常規布局是基于塊與行內元素的流向的,那么flex布局則是基于“flex流向”的。請看來自w3c規范中的這張圖,解釋了flex布局的主要思想:
通常,伸縮項目的布局要么按照主軸(main axis)方向,從主軸起點(main-start)到主軸終點(main-end),要么按照交叉軸(cross axis)方向,從交叉軸起點(cross-start)到交叉軸終點(cross-end)。
主軸(main axis) - 伸縮容器的主軸,是伸縮項目布局遵循的主要方向。注意:這個方向不一定是水平方向;它取決于“flex-direction”屬性的值(見下文);
主軸起點(main-start) | 主軸終點(main-end ) - 伸縮項目置于容器中,從主軸起點(main-start)到主軸終點(main-end);
主體大小(main size) - 伸縮項目的寬度或高度就是主體大小,不管主維度是哪個。伸縮項目的主體大小要么是‘width’屬性,要么是‘height’屬性,不管主維度是哪一個。
交叉軸(cross axis) - 與主軸垂直的軸稱為交叉軸(cross axis), 它的方向取決于主軸(main axis)的方向;
交叉軸起點(cross-start) | 交叉軸終點(cross-end) - 伸縮行填充著伸縮項目,并放置于伸縮容器中,從伸縮容器交叉軸起點開始,沿著交叉軸終點方向;
交叉方向大小(cross size) – 伸縮項目的寬度或高度就是交叉方向的大小,不管交叉維度是哪一個。交叉方向大小屬性要么是交叉軸維度的寬度要么是交叉軸維度的高度。
父元素(伸縮容器)屬性
display
display屬性用來定義伸縮容器,容器是行內元素或者塊元素取決于給定的值,這個屬性開啟了容器內所有直接子元素的flex上下文。
CSS:
.container {
display: flex; /*or inline-flex*/
}
注意:CSS columns對于伸縮容器沒有作用。
flex-direction
這個屬性建立了主軸方向,定義了伸縮項目在伸縮容器內排列的方向。Flexbox是一個單一方向布局的概念。可以認為伸縮項目或者沿水平方向或者沿垂直方向布局。
CSS:
.container {
flex-direction: row | row-reverse | column | column-reverse;
}
row(默認值): 在‘ltr’排版中從左到右,‘rtl’排版中從右到左;
row-reverse: "ltr"中從右到左,‘ltr’中從左到右;
column: 與row屬性一樣,但是是從頂部到底部;
column-reverse: 與row-reverse一樣,但是是從底部到頂部。
flex-wrap
默認情況下,伸縮項目會盡量排成一行。當然,可以根據需要讓伸縮項目換行來改變它。此時,方向也很重要,它決定了下一行堆疊的方向。
CSS:
.container {
flex-wrap: nowrap | wrap | wrap-reverse;
}
nowrap(默認):單行模式/"ltr"中從左到右,"rtl"中從右到左;
wrap: 多行模式/"ltr"中從左到右,"rtl"中從右到左
wrap-reverse: 多行模式/"ltr"中從右到左,"rtl"中從左到右;
flex-flow(適用于:伸縮容器,也就是父元素)
這是"flex-direction"和 "flex-wrap"屬性的快捷形式,它同時定義了伸縮容器的主軸和交叉軸。默認值是row nowrap。
CSS:
flex-flow: <"flex-direction"> || <"flex-wrap">
justify-content
justify-content定義了沿著主軸的排列方式。當一行中的所有伸縮項目都不能再伸縮時,或者能伸縮但已經達到了自身最大尺寸時,這個屬性負責分配剩余的自由空間。同時它也能在溢出時對排列元素進行一定的控制。
CSS:
.container {
justify-content: flex-start | flex-end | center | space-between | space-around
}
flex-start(默認值):伸縮項目朝著起點方向緊湊排列;
flex-end: 伸縮項目朝著終點方向緊湊排列;
space-between: 伸縮項目在一行中平均分配,第一個項目在起點處,最后一個項目在終點處;
space-around: 伸縮項目兩側的空間保持相等,在一行中平均分配。值得注意的是在視覺上,一個項目兩邊的空間是不相等的,因為所有項目都是在自身的兩邊分配了相等的空間。第一個項目在容器邊緣分配得到一份空間,但是第二個項目的左邊會分得兩份空間,因為它自身的也有一份分配的空間。
align-items
align-items定義了伸縮項目沿著交叉軸當前方向的布局方式。可以把它看成交叉軸方向的justify-content版本。
CSS:
.container {
align-items: flex-start | flex-end | center | baseline | stretch;
}
flex-start: 伸縮項目的起點放置在交叉軸線的起點上;
flex-end: 伸縮項目的終點放置在交叉軸線的終點上;
center: 伸縮項目置于交叉軸線的中心;
baseline: 伸縮項目按照他們的基線排列;
stetch(默認): 拉伸以填滿容器(仍然遵循min-width/max-width)
align-content
align-content定義了伸縮容器當在交叉軸上有多余空間時的排列線,和主軸方向上justify-content排列伸縮項目類似。
注意:這個屬性在只有一行伸縮項目時無效。
CSS:
.container {
algin-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
flex-start: 緊鄰容器起始排列;
flex-end: 緊鄰容器終點排列;
center: 排列在容器中間;
space-between: 平均分配,第一行在容器起始處而最后一行在容器末尾處;
space-around: 平均分配,每行兩邊距離相等;
stretch(默認值): 拉伸項目來占據剩余空間;
子元素屬性(伸縮項目)
order
默認情況下,伸縮項目按照文檔流出現的先后順序排列。但order屬性可以控制在伸縮容器內的顯示順序。
CSS:
.item {
order: ;
}
flex-grow
flex-grow定義了伸縮項目必要時擴展的能力。它接受一個無單位的值作為比例。它指定了伸縮容器內伸縮項目能伸展的可用空間的大小。
如果所有伸縮項目的flex-grow屬性設置為1,容器中剩余空間會被均等分配給所有子元素。如果一個子元素的flex-grow設置為2,那么它占據的剩余空間中會是其他子元素占據空間的兩倍。
CSS:
.item {
flex-grow: ; /*default 0*/
}
負數無效。
flex-shrink
flex-shrink定義了伸縮項目根據需要收縮的能力。
.item {
flex-shrink: ; /*default 1*/
}
負數無效。
flex-basis
定義了元素在剩余空間被分配之前的默認大小。它的值可以是長度(例如20%, 5rem等),也可以是關鍵詞。"auto"表明元素的大小取決于元素的寬度或高度屬性(臨時由main-size屬性決定)。"content"表明元素大小取決于伸縮項目內容的大小-目前尚不支持,因此max-content,min-content,fit-content這些兄弟屬性較難測試和分析。
CSS:
.item {
flex-basis: | 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
允許默認對齊方式(或者由align-items定義的對齊方式)能被單個伸縮項目覆蓋。
CSS:
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
注意:float,clear,vertical-align屬性對伸縮項目沒有作用。
Examples
我們先從一個非常簡單的例子開始,解決一個最常見的問題:居中。使用flexbox你會發現簡直不能更容易了。
CSS:
.parent {
display: flex;
height: 300px; /*Or whatever*/
}
.child {
width: 100px; /*Or whatever*/
height: 100px; /*Or whatever*/
margin: auto; /*Magic! */
}
這依賴于一個特性:伸縮容器里的元素的margin值如果設置了"auto",能自動均衡容器中剩余的空間。所以在垂直方向也設置了auto后,能使得伸縮項目在兩個軸線方向上都完美居中。
現在,讓我們來使用更多屬性。考慮有一個有6個條目的列表,每一個都是固定大小的,但他們可以被調整大小的。我們希望它們能平均地分布在水平軸上,這樣當我們調整瀏覽器時,依然能良好地顯示(不使用媒體查詢)。
.flex-container {
/*首先創建一個伸縮容器*/
display: flex;
/*然后定義伸縮流方向,并且伸縮項目能換行
* 記住這個設置等同于下面這兩個設置:
* flex-direction: row;
* flex-wrap: wrap;
*/
flex-flow: row wrap;
/*然后定義剩余空間如何分配*/
justify-content: space-around;
}
好了。剩下的僅僅是樣式的問題了。
下面是一個闡述這個屬性的具體例子。試試去CodePen上查看,再調整瀏覽器窗口看看會發生什么。
HTML:
SCSS:
@import "compass/css3";
.flex-container {
padding: 0;
margin: 0;
list-style: none;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row wrap;
justify-content: space-around;
}
.flex-item {
background: tomato;
padding: 5px;
width: 200px;
height: 150px;
margin-top: 10px;
line-height: 150px;
color: white;
font-weight: bold;
font-size: 3em;
text-align: center;
}
這是在PC正常顯示屏幕下的效果(瀏覽器寬度約為1190px)的效果:
縮小瀏覽器,6個盒子的排列會隨瀏覽器寬度的大小進行調整,這是瀏覽器寬度小于約700px時的效果:
隨著瀏覽器繼續縮小,最終6個盒子會變為逐個縱向排列的布局形式。
再試試別的屬性。設想網站頂部有一個靠右對齊的導航,我們希望它在中等大小的屏幕和單一欄目的小屏幕上都居中顯示。非常容易:
CSS:
/* 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;
}
}
具體示例代碼:
HTML:
SCSS:
@import "compass/css3";
.navigation {
list-style: none;
margin: 0;
background: deepskyblue;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row wrap;
justify-content: flex-end;
}
.navigation a {
text-decoration: none;
display: block;
padding: 1em;
color: white;
}
.navigation a:hover {
background: darken(deepskyblue, 2%);
}
@media all and (max-width: 800px) {
.navigation {
justify-content: space-around;
}
}
@media all and (max-width: 600px) {
.navigation {
-webkit-flex-flow: column wrap;
flex-flow: column wrap;
padding: 0;
}
.navigation a {
text-align: center;
padding: 10px;
border-top: 1px solid rgba(255,255,255,0.3);
border-bottom: 1px solid rgba(0,0,0,0.1);
}
.navigation li:last-of-type a {
border-bottom: none;
}
}
上述示例結果圖:
縮小瀏覽器,寬度小于等于600px時:
現在讓我們再嘗試一下伸縮項目上的屬性!比如一個手機上的三欄布局,其中頭部和尾部占據全屏。并且不管它們在文檔流的順序。
CSS:
.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; }
}
具體示例代碼:
HTML:
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
SCSS:
@import "compass/css3";
.wrapper {
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row wrap;
flex-flow: row wrap;
font-weight: bold;
text-align: center;
}
.wrapper > * {
padding: 10px;
flex: 1 100%;
}
.header {
background: tomato;
}
.footer {
background: lightgreen;
}
.main {
text-align: left;
background: deepskyblue;
}
.aside-1 {
background: gold;
}
.aside-2 {
background: hotpink;
}
@media all and (min-width: 600px) {
.aside { flex: 1 auto; }
}
@media all and (min-width: 800px) {
.main { flex: 3 0px; }
.aside-1 { order: 1; }
.main { order: 2; }
.aside-2 { order: 3; }
.footer { order: 4; }
}
body {
padding: 2em;
}
上述示例結果圖:
縮小瀏覽器,寬度小于等于600px時:
Flexbox 前綴
Flexbox需要書寫較多的前綴以支持大多數瀏覽器下的顯示。這里指的不僅僅包括(在屬性前)加入瀏覽器的前綴,實際上還包含加入其它一些不一樣的屬性和屬性值。這是因為Flexbox規范一直在向前發展,先后創建了"old", "tweener"和"new"幾個版本。
也許更好的處理辦法是使用新語法,并通過Autoprefixer來運行你的CSS。
這里給出一個Sass @mixin的示例可以幫助解決一些前綴問題,或許可以給你提供一些思路:
SCSS:
@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)link
Flexplorer by Bennett Feely
Bugs
Flexbox 并非沒有bug. 我看過的最好的收集這方面bug的是Philip Walton and Greg Whitworth的Flexbugs。 這是一個開源的跟蹤問題的地方。
瀏覽器支持
這個要區分一下flexbox的版本:
(new)表明規范上最新的語法(例如:display:flex;);
(tweener)表明是2011年舊版的非官方語法(例如:display: flexbox;);
(old)表明是2009年舊版語法(例如:display:box)。
Blackberry瀏覽器10+支持新版語法。
更多關于如何混合使用語法來最好地讓flexbox得到瀏覽器的支持,請參考這篇文章或這篇