摘要:本文譯自這里,針對本文介紹的屬性列個(gè)提綱伸縮容器屬性伸縮項(xiàng)目屬性以后再布局時(shí)可以考慮用啦背景布局模塊目前上一次工作草案的叫法旨在提供一種更高效的方式來布局排列及分配容器中項(xiàng)目的空間,即便容器大小是未知或動(dòng)態(tài)變化的因此稱為。
本文譯自 A Complete Guide to Flexbox
這里,針對本文介紹的屬性列個(gè)提綱:
伸縮容器屬性:
display
flex-direction
flex-wrap
flex-flow
justify-content
align-items
align-content
伸縮項(xiàng)目屬性:
order
flex-grow
flex-shrink
flex-basis
flex
align-self
以后再布局時(shí)可以考慮用flexbox啦~~
背景
Flexbox 布局(Flexible Box)模塊(目前W3C上一次工作草案的叫法)旨在提供一種更高效的方式來布局、排列及分配容器中項(xiàng)目的空間,即便容器大小是未知或動(dòng)態(tài)變化的(因此稱為“flex”)。
Flex布局的主要思想是使容器具備改變其子項(xiàng)目的寬度或高度的能力,以此充分填充可用空間(主要是為了適應(yīng)各種顯示設(shè)備和屏幕尺寸)。使用flex布局的容器能擴(kuò)展其子項(xiàng)目來填滿可用空間,也能縮小他們以防止溢出容器。
Flex布局與常規(guī)布局相比,最主要的是它是方向無關(guān)的(常規(guī)布局通常是塊級(jí)元素從上到下布局,行內(nèi)元素從左到右布局)。盡管常規(guī)布局對于頁面布局十分好用,但卻缺少對大型或復(fù)雜應(yīng)用的靈活性支持(尤其是當(dāng)涉及到取向改變,尺寸調(diào)整,拉伸,收縮等場景時(shí))。
注意:Flexbox布局主要適用于應(yīng)用的組件以及小規(guī)模的布局,對于那些較大規(guī)模的布局網(wǎng)格布局更適用。
基本概念&術(shù)語
Flexbox是一整個(gè)模塊,并非單一的一個(gè)屬性,它涉及的東西比較多,包括一系列屬性。其中一些屬性是用在容器(父元素,即伸縮容器)上的,其他一些屬性則是用在子元素(伸縮項(xiàng)目)上的。
如果說常規(guī)布局是基于塊與行內(nèi)元素的流向的,那么flex布局則是基于“flex流向”的。請看來自w3c規(guī)范中的這張圖,解釋了flex布局的主要思想:
通常,伸縮項(xiàng)目的布局要么按照主軸(main axis)方向,從主軸起點(diǎn)(main-start)到主軸終點(diǎn)(main-end),要么按照交叉軸(cross axis)方向,從交叉軸起點(diǎn)(cross-start)到交叉軸終點(diǎn)(cross-end)。
主軸(main axis) - 伸縮容器的主軸,是伸縮項(xiàng)目布局遵循的主要方向。注意:這個(gè)方向不一定是水平方向;它取決于“flex-direction”屬性的值(見下文);
主軸起點(diǎn)(main-start) | 主軸終點(diǎn)(main-end ) - 伸縮項(xiàng)目置于容器中,從主軸起點(diǎn)(main-start)到主軸終點(diǎn)(main-end);
主體大小(main size) - 伸縮項(xiàng)目的寬度或高度就是主體大小,不管主維度是哪個(gè)。伸縮項(xiàng)目的主體大小要么是‘width’屬性,要么是‘height’屬性,不管主維度是哪一個(gè)。
交叉軸(cross axis) - 與主軸垂直的軸稱為交叉軸(cross axis), 它的方向取決于主軸(main axis)的方向;
交叉軸起點(diǎn)(cross-start) | 交叉軸終點(diǎn)(cross-end) - 伸縮行填充著伸縮項(xiàng)目,并放置于伸縮容器中,從伸縮容器交叉軸起點(diǎn)開始,沿著交叉軸終點(diǎn)方向;
交叉方向大小(cross size) – 伸縮項(xiàng)目的寬度或高度就是交叉方向的大小,不管交叉維度是哪一個(gè)。交叉方向大小屬性要么是交叉軸維度的寬度要么是交叉軸維度的高度。
父元素(伸縮容器)屬性
display
display屬性用來定義伸縮容器,容器是行內(nèi)元素或者塊元素取決于給定的值,這個(gè)屬性開啟了容器內(nèi)所有直接子元素的flex上下文。
CSS:
.container {
display: flex; /*or inline-flex*/
}
注意:CSS columns對于伸縮容器沒有作用。
flex-direction
這個(gè)屬性建立了主軸方向,定義了伸縮項(xiàng)目在伸縮容器內(nèi)排列的方向。Flexbox是一個(gè)單一方向布局的概念??梢哉J(rèn)為伸縮項(xiàng)目或者沿水平方向或者沿垂直方向布局。
CSS:
.container {
flex-direction: row | row-reverse | column | column-reverse;
}
row(默認(rèn)值): 在‘ltr’排版中從左到右,‘rtl’排版中從右到左;
row-reverse: "ltr"中從右到左,‘ltr’中從左到右;
column: 與row屬性一樣,但是是從頂部到底部;
column-reverse: 與row-reverse一樣,但是是從底部到頂部。
flex-wrap
默認(rèn)情況下,伸縮項(xiàng)目會(huì)盡量排成一行。當(dāng)然,可以根據(jù)需要讓伸縮項(xiàng)目換行來改變它。此時(shí),方向也很重要,它決定了下一行堆疊的方向。
CSS:
.container {
flex-wrap: nowrap | wrap | wrap-reverse;
}
nowrap(默認(rèn)):單行模式/"ltr"中從左到右,"rtl"中從右到左;
wrap: 多行模式/"ltr"中從左到右,"rtl"中從右到左
wrap-reverse: 多行模式/"ltr"中從右到左,"rtl"中從左到右;
flex-flow(適用于:伸縮容器,也就是父元素)
這是"flex-direction"和 "flex-wrap"屬性的快捷形式,它同時(shí)定義了伸縮容器的主軸和交叉軸。默認(rèn)值是row nowrap。
CSS:
flex-flow: <"flex-direction"> || <"flex-wrap">
justify-content
justify-content定義了沿著主軸的排列方式。當(dāng)一行中的所有伸縮項(xiàng)目都不能再伸縮時(shí),或者能伸縮但已經(jīng)達(dá)到了自身最大尺寸時(shí),這個(gè)屬性負(fù)責(zé)分配剩余的自由空間。同時(shí)它也能在溢出時(shí)對排列元素進(jìn)行一定的控制。
CSS:
.container {
justify-content: flex-start | flex-end | center | space-between | space-around
}
flex-start(默認(rèn)值):伸縮項(xiàng)目朝著起點(diǎn)方向緊湊排列;
flex-end: 伸縮項(xiàng)目朝著終點(diǎn)方向緊湊排列;
space-between: 伸縮項(xiàng)目在一行中平均分配,第一個(gè)項(xiàng)目在起點(diǎn)處,最后一個(gè)項(xiàng)目在終點(diǎn)處;
space-around: 伸縮項(xiàng)目兩側(cè)的空間保持相等,在一行中平均分配。值得注意的是在視覺上,一個(gè)項(xiàng)目兩邊的空間是不相等的,因?yàn)樗许?xiàng)目都是在自身的兩邊分配了相等的空間。第一個(gè)項(xiàng)目在容器邊緣分配得到一份空間,但是第二個(gè)項(xiàng)目的左邊會(huì)分得兩份空間,因?yàn)樗陨淼囊灿幸环莘峙涞目臻g。
align-items
align-items定義了伸縮項(xiàng)目沿著交叉軸當(dāng)前方向的布局方式??梢园阉闯山徊孑S方向的justify-content版本。
CSS:
.container {
align-items: flex-start | flex-end | center | baseline | stretch;
}
flex-start: 伸縮項(xiàng)目的起點(diǎn)放置在交叉軸線的起點(diǎn)上;
flex-end: 伸縮項(xiàng)目的終點(diǎn)放置在交叉軸線的終點(diǎn)上;
center: 伸縮項(xiàng)目置于交叉軸線的中心;
baseline: 伸縮項(xiàng)目按照他們的基線排列;
stetch(默認(rèn)): 拉伸以填滿容器(仍然遵循min-width/max-width)
align-content
align-content定義了伸縮容器當(dāng)在交叉軸上有多余空間時(shí)的排列線,和主軸方向上justify-content排列伸縮項(xiàng)目類似。
注意:這個(gè)屬性在只有一行伸縮項(xiàng)目時(shí)無效。
CSS:
.container {
algin-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
flex-start: 緊鄰容器起始排列;
flex-end: 緊鄰容器終點(diǎn)排列;
center: 排列在容器中間;
space-between: 平均分配,第一行在容器起始處而最后一行在容器末尾處;
space-around: 平均分配,每行兩邊距離相等;
stretch(默認(rèn)值): 拉伸項(xiàng)目來占據(jù)剩余空間;
子元素屬性(伸縮項(xiàng)目)
order
默認(rèn)情況下,伸縮項(xiàng)目按照文檔流出現(xiàn)的先后順序排列。但order屬性可以控制在伸縮容器內(nèi)的顯示順序。
CSS:
.item {
order: ;
}
flex-grow
flex-grow定義了伸縮項(xiàng)目必要時(shí)擴(kuò)展的能力。它接受一個(gè)無單位的值作為比例。它指定了伸縮容器內(nèi)伸縮項(xiàng)目能伸展的可用空間的大小。
如果所有伸縮項(xiàng)目的flex-grow屬性設(shè)置為1,容器中剩余空間會(huì)被均等分配給所有子元素。如果一個(gè)子元素的flex-grow設(shè)置為2,那么它占據(jù)的剩余空間中會(huì)是其他子元素占據(jù)空間的兩倍。
CSS:
.item {
flex-grow: ; /*default 0*/
}
負(fù)數(shù)無效。
flex-shrink
flex-shrink定義了伸縮項(xiàng)目根據(jù)需要收縮的能力。
.item {
flex-shrink: ; /*default 1*/
}
負(fù)數(shù)無效。
flex-basis
定義了元素在剩余空間被分配之前的默認(rèn)大小。它的值可以是長度(例如20%, 5rem等),也可以是關(guān)鍵詞。"auto"表明元素的大小取決于元素的寬度或高度屬性(臨時(shí)由main-size屬性決定)。"content"表明元素大小取決于伸縮項(xiàng)目內(nèi)容的大小-目前尚不支持,因此max-content,min-content,fit-content這些兄弟屬性較難測試和分析。
CSS:
.item {
flex-basis: | auto; /*default auto*/
}
如果設(shè)置為0,內(nèi)容區(qū)域周圍的多余空間將不被考慮,如果設(shè)置為auto, 多余空間會(huì)基于flex-grow值來分配。參考下圖。
flex
這是結(jié)合flex-grow,flex-shrink,flex-basis屬性的簡易寫法。第二個(gè)屬性flex-shrink和第三個(gè)屬性flex-basis是可選的。默認(rèn)值是0 1 auto;
.item {
flex:none | [ <"flex-grow"> <"flex-shrink"> ? || <"flex-basis"> ]
}
推薦使用這個(gè)快捷形式的屬性,比逐個(gè)設(shè)置屬性好用。它能自動(dòng)設(shè)置所有屬性的值。
align-self
允許默認(rèn)對齊方式(或者由align-items定義的對齊方式)能被單個(gè)伸縮項(xiàng)目覆蓋。
CSS:
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
注意:float,clear,vertical-align屬性對伸縮項(xiàng)目沒有作用。
Examples
我們先從一個(gè)非常簡單的例子開始,解決一個(gè)最常見的問題:居中。使用flexbox你會(huì)發(fā)現(xiàn)簡直不能更容易了。
CSS:
.parent {
display: flex;
height: 300px; /*Or whatever*/
}
.child {
width: 100px; /*Or whatever*/
height: 100px; /*Or whatever*/
margin: auto; /*Magic! */
}
這依賴于一個(gè)特性:伸縮容器里的元素的margin值如果設(shè)置了"auto",能自動(dòng)均衡容器中剩余的空間。所以在垂直方向也設(shè)置了auto后,能使得伸縮項(xiàng)目在兩個(gè)軸線方向上都完美居中。
現(xiàn)在,讓我們來使用更多屬性??紤]有一個(gè)有6個(gè)條目的列表,每一個(gè)都是固定大小的,但他們可以被調(diào)整大小的。我們希望它們能平均地分布在水平軸上,這樣當(dāng)我們調(diào)整瀏覽器時(shí),依然能良好地顯示(不使用媒體查詢)。
.flex-container {
/*首先創(chuàng)建一個(gè)伸縮容器*/
display: flex;
/*然后定義伸縮流方向,并且伸縮項(xiàng)目能換行
* 記住這個(gè)設(shè)置等同于下面這兩個(gè)設(shè)置:
* flex-direction: row;
* flex-wrap: wrap;
*/
flex-flow: row wrap;
/*然后定義剩余空間如何分配*/
justify-content: space-around;
}
好了。剩下的僅僅是樣式的問題了。
下面是一個(gè)闡述這個(gè)屬性的具體例子。試試去CodePen上查看,再調(diào)整瀏覽器窗口看看會(huì)發(fā)生什么。
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個(gè)盒子的排列會(huì)隨瀏覽器寬度的大小進(jìn)行調(diào)整,這是瀏覽器寬度小于約700px時(shí)的效果:
隨著瀏覽器繼續(xù)縮小,最終6個(gè)盒子會(huì)變?yōu)橹饌€(gè)縱向排列的布局形式。
再試試別的屬性。設(shè)想網(wǎng)站頂部有一個(gè)靠右對齊的導(dǎo)航,我們希望它在中等大小的屏幕和單一欄目的小屏幕上都居中顯示。非常容易:
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;
}
}
上述示例結(jié)果圖:
縮小瀏覽器,寬度小于等于600px時(shí):
現(xiàn)在讓我們再嘗試一下伸縮項(xiàng)目上的屬性!比如一個(gè)手機(jī)上的三欄布局,其中頭部和尾部占據(jù)全屏。并且不管它們在文檔流的順序。
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;
}
上述示例結(jié)果圖:
縮小瀏覽器,寬度小于等于600px時(shí):
Flexbox 前綴
Flexbox需要書寫較多的前綴以支持大多數(shù)瀏覽器下的顯示。這里指的不僅僅包括(在屬性前)加入瀏覽器的前綴,實(shí)際上還包含加入其它一些不一樣的屬性和屬性值。這是因?yàn)镕lexbox規(guī)范一直在向前發(fā)展,先后創(chuàng)建了"old", "tweener"和"new"幾個(gè)版本。
也許更好的處理辦法是使用新語法,并通過Autoprefixer來運(yùn)行你的CSS。
這里給出一個(gè)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);
}
相關(guān)屬性
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。 這是一個(gè)開源的跟蹤問題的地方。
瀏覽器支持
這個(gè)要區(qū)分一下flexbox的版本:
(new)表明規(guī)范上最新的語法(例如:display:flex;);
(tweener)表明是2011年舊版的非官方語法(例如:display: flexbox;);
(old)表明是2009年舊版語法(例如:display:box)。
Blackberry瀏覽器10+支持新版語法。
更多關(guān)于如何混合使用語法來最好地讓flexbox得到瀏覽器的支持,請參考這篇文章或這篇