你真的理解 flex 佈局嗎?

Coderfei發表於2019-04-29
網頁佈局(layout)是CSS的一個重點應用。

佈局的傳統解決方案,基於盒狀模型,依賴 display屬性 + position屬性 + float屬性。它對於那些特殊佈局非常不方便,比如,垂直居中就不容易實現。

2009年,W3C提出了一種新的方案—-Flex佈局,可以簡便、完整、響應式地實現各種頁面佈局。目前,它已經得到了所有瀏覽器的支援,這意味著,現在就能很安全地使用這項功能。

Flex佈局將成為未來佈局的首選方案。本文介紹Flex佈局的語法。

一、Flex佈局簡介

Flex英文為 flexiable box,翻譯為彈性盒子,Flex佈局即彈性佈局。

Flex佈局為盒子模型提供了很大的靈活性,任何一個容器都可以指定為Flex佈局,設定方法為:

.box{
  display: flex;
}複製程式碼

行內元素也可以使用Flex佈局。

.box{
  display: inline-flex;
}複製程式碼

Webkit核心的瀏覽器,必須加上-webkit字首。

.box{
  display: -webkit-flex; /* Safari */
  display: flex;
}複製程式碼

注意,設為Flex佈局以後,子元素的float、clear和vertical-align屬性將失效,(而且可以巢狀使用。)

二、基本概念

採用Flex佈局的元素,稱為Flex容器(flex container),簡稱”容器”。它的所有子元素自動成為容器成員,稱為Flex專案(flex item),簡稱”專案”。

容器預設存在兩根軸:水平的主軸(main axis)和垂直的交叉軸(cross axis)。主軸的開始位置(與邊框的交叉點)叫做main start,結束位置叫做main end;交叉軸的開始位置叫做cross start,結束位置叫做cross end。

專案預設沿主軸排列。單個專案佔據的主軸空間叫做main size,佔據的交叉軸空間叫做cross size。

三、容器的屬性

flex-direction;
flex-wrap;
flex-flow;
justify-content;
align-items;
align-content;複製程式碼

3.1 flex-direction屬性

flex-direction屬性決定主軸的方向(即專案的排列方向)。它可能有四個值:

.box {
  flex-direction: row | row-reverse | column | column-reverse;
}複製程式碼
flex-direction : row(預設值),主軸為水平方向,起點在左端。效果:

你真的理解 flex 佈局嗎?flex-direction : row-reverse,主軸為水平方向,起點在右端。效果:

你真的理解 flex 佈局嗎?

flex-direction : column,主軸為垂直方向,起點在上沿。效果:

你真的理解 flex 佈局嗎?

flex-direction : column-reverse,主軸為垂直方向,起點在下沿。效果:

你真的理解 flex 佈局嗎?

完整程式碼 :

HTML 部 分:
<div class="box">    
    <span>love1</span>    
    <span>love2</span>    
    <span>love3</span>    
    <span>love4</span></div>
CSS 部分:
<style>    
    .box{        
        display: flex;        
        display: -webkit-flex;        
        /*水平方向,左端對齊*/        
        flex-direction: row;        
        /*水平方向,右端對齊*/        
        /* flex-direction: row-reverse; */        
        /*垂直方向,頂部對齊*/        
        /* flex-direction: column; */        
        /*垂直方向,底部對齊*/        
        /* flex-direction: column-reverse; */        
        background: #999;        
        width: 100%;    
    }        
    .box span{            
        margin: 10px 10px;            
        padding: 10px;            
        background: #ff0;            
        width: 50px;        
    }    
</style>
複製程式碼

3.2 flex-wrap屬性

預設情況下,專案都排在一條線(又稱”軸線”)上。flex-wrap屬性定義,如果一條軸線排不下,如何換行。它可能取三個值。

.box{
  flex-wrap: nowrap | wrap | wrap-reverse;
}複製程式碼

(1)當設定為 flex-wrap : nowrap(預設),效果(不換行,預設會縮放):

你真的理解 flex 佈局嗎?

(2)flex-wrap : wrap,換行,第一行在上方。

你真的理解 flex 佈局嗎?

(3)flex-wrap : wrap-reverse,換行,第一行在下方。

你真的理解 flex 佈局嗎?

完整程式碼:

<style>        
    .box{            
        display: flex;            
        display: -webkit-flex;            
        /*不換行,預設*/            
        /* flex-wrap: nowrap; */            
        /*換行*/            
        /* flex-wrap: wrap; */            
        /*換行,第一行在下方*/            
        /* flex-wrap: wrap-reverse; */            
        background: #999;            
        width: 100%;        
    }        
    .box span{           
        margin: 10px 10px;            
        padding: 10px;            
        background: #ff0;            
        width: 50px;        
    }    
</style>

HTML 程式碼:    
<div class="box">        
    <span>love1</span>        
    <span>love2</span>        
    <span>love3</span>        
    <span>love4</span>        
    <span>love5</span>        
    <span>love6</span>        
    <span>love7</span>        
    <span>love8</span>   
</div> 
複製程式碼

3.3 flex-flow 屬性

flex-flow 屬性是 flex-direction 屬性和 flex-wrap 屬性的簡寫形式,預設值為 row nowrap。

.box {
  flex-flow: <flex-direction> <flex-wrap>;
}複製程式碼

3.4 justify-content屬性

justify-content屬性定義了專案在主軸上的對齊方式。

.box {
  justify-content: flex-start | flex-end | center | space-between | space-around;
}複製程式碼

它可能取5個值,具體對齊方式與軸的方向有關。下面假設主軸為從左到右。

justify-content : flex-start(預設值),左對齊

你真的理解 flex 佈局嗎?

justify-content : flex-end,右對齊

你真的理解 flex 佈局嗎?

justify-content : center,居中

你真的理解 flex 佈局嗎?

justify-content : space-between,兩端對齊,專案之間的間隔都相等。

你真的理解 flex 佈局嗎?

justify-content : space-around,每個專案兩側的間隔相等。所以,專案之間的間隔比專案與邊框的間隔大一倍。

你真的理解 flex 佈局嗎?

完整程式碼:

CSS程式碼:
<style>        
    .box{            
        display: flex;            
        display: -webkit-flex;            
        /*預設,專案左對齊*/            
        /* justify-content: flex-start; */            
        /*專案右對齊*/            
        /* justify-content: flex-end; */            
        /*專案居中對齊*/            
        /* justify-content: center; */            
        /*專案兩端對齊*/            
        /* justify-content: space-between; */            
        /*每個專案兩側的間隔相等*/            
        justify-content: space-around;            
        background: #999;            
        width: 100%;        }        
    .box span{            
        margin: 10px 10px;            
        padding: 10px;            
        background: #ff0;            
        width: 50px;        
    }    
</style>
HTML程式碼:
<div class="box">        
    <span>love1</span>        
    <span>love2</span>        
    <span>love3</span>        
    <span>love4</span>        
    <span>love5</span>        
    <span>love6</span>        
    <span>love7</span>        
    <span>love8</span>    
</div>
複製程式碼


3.5 align-items屬性

align-items屬性定義專案在交叉軸上如何對齊。

.box {
  align-items: flex-start | flex-end | center | baseline | stretch;
}複製程式碼

它可能取5個值。具體的對齊方式與交叉軸的方向有關,下面假設交叉軸從上到下。

align-items : flex-start,交叉軸的起點對齊。

你真的理解 flex 佈局嗎?

align-items : flex-end,交叉軸的終點對齊。

你真的理解 flex 佈局嗎?

align-items : center,交叉軸的中點對齊。

你真的理解 flex 佈局嗎?

align-items : baseline,專案的第一行文字的基線對齊。

你真的理解 flex 佈局嗎?

align-items : stretch(預設值),如果專案未設定高度或設為auto,將佔滿整個容器的高度。

你真的理解 flex 佈局嗎?

完整程式碼:

<style type="text/css">
.box{
    display: flex;
    display: -webkit-flex;
    /*縱軸的頂部對齊*/
    /*align-items: flex-start;*/
    /*縱軸的底部對齊*/
    /*align-items: flex-end;*/
    /*縱軸的中點對齊*/
    /*align-items: center;*/
    /*專案的第一行文字的基線對齊*/
    /*align-items: baseline;*/
    /*預設對齊方式,如果專案未設定高度或設為auto,將佔滿整個容器的高度*/
    align-items: stretch;
    background: #999;
    width: 100%;
}
.box span{
    margin: 10px 10px;
    padding: 10px;
    background: #ff0;
    width: 50px;
}
.box span:nth-of-type(2n){
    height: 80px;
    padding-top: 20px;
}
</style>
<div class="box">
    <span>love1</span>
    <span>love2</span>
    <span>love3</span>
    <span>love4</span>
    <span>love5</span>
    <span>love6</span>
    <span>love7</span>
    <span>love8</span>
</div>複製程式碼

3.6 align-content屬性

align-content 屬性定義了多根軸線的對齊方式。如果專案只有一根軸線,該屬性不起作用 (即需要設定容器的 flex-wrap 屬性值為 wrap )(為了讓效更加明顯,我設定了容器的高度)

.box {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}複製程式碼

該屬性可能取6個值。

align-content : flex-start,與交叉軸的起點對齊。

你真的理解 flex 佈局嗎?

align-content : flex-end,與交叉軸的終點對齊。

你真的理解 flex 佈局嗎?

align-content : center,與交叉軸的中點對齊。

你真的理解 flex 佈局嗎?

align-content : space-between,與交叉軸兩端對齊,軸線之間的間隔平均分佈。

你真的理解 flex 佈局嗎?

align-content : space-around,每根軸線兩側的間隔都相等。所以,軸線之間的間隔比軸線與邊框的間隔大一倍。

你真的理解 flex 佈局嗎?

align-content : stretch(預設值),軸線佔滿整個交叉軸。

你真的理解 flex 佈局嗎?

完整程式碼:

CSS 程式碼:
<style>        
    .box{            
        display: flex;            
        display: -webkit-flex;
        //如果專案只有一根軸線,該屬性不起作用 (即需要設定容器的 flex-wrap 屬性值為 wrap )
        flex-wrap: wrap;
        /*與縱軸的頂部對齊*/            
        /*align-content: flex-start;*/ 
           
        /*與縱軸的底部對齊*/           
        /*align-content: flex-end;*/   
         
        /*與縱軸的中點對齊*/            
        /*align-content: center;*/   
         
        /*與縱軸兩端對齊*/            
        /*align-content: space-between;*/ 
           
        /*每根軸線兩側的間隔都相等*/            
        align-content: space-around;     
       
        /*預設值,軸線佔滿整個交叉軸預設值,*/            
        /* align-content: stretch; */   
         
        background: #999;            
        width: 600px;            
        height: 300px;        
    }        
    .box span{            
        margin: 10px 10px;            
        padding: 10px;            
        background: #ff0;            
        width: 50px;        
    }    
</style>

HTML 程式碼:
<div class="box">       
    <span>love1</span>        
    <span>love2</span>        
    <span>love3</span>        
    <span>love4</span>        
    <span>love5</span>        
    <span>love6</span>        
    <span>love7</span>        
    <span>love8</span>    
</div>複製程式碼

四、專案的屬性

以下6個屬性設定在專案上。

  • order
  • flex-grow
  • flex-shrink
  • flex-basis
  • flex
  • align-self

4.1 order屬性

order屬性定義專案的排列順序。數值越小,排列越靠前,預設為0。

.item {
  order: <integer>;
}複製程式碼

如下為第1個設定order屬性為10,第2個設定order屬性為-1,第5個設定order屬性為-10,效果如下你真的理解 flex 佈局嗎?

程式碼:

CSS:
<style>        
    .box{            
        display: flex;           
        display: -webkit-flex;            
        background: #999;        
    }        
    .box span{            
        margin: 10px 10px;            
        padding: 10px;            
        background: #ff0;        
    }        
    .box span:nth-of-type(1){            
        order: 10;        
    }        
    .box span:nth-of-type(2){            
        order: -1;        
    }        
    .box span:nth-of-type(5){            
        order: -10;        
    }   
</style>

HTML 程式碼:
<div class="box">        
    <span>love1</span>        
    <span>love2</span>        
    <span>love3</span>        
    <span>love4</span>        
    <span>love5</span>    
</div>
複製程式碼


4.2 flex-grow屬性

flex-grow屬性定義專案的放大比例,主要在父元素的寬度大於子元素的寬度之和時候起作用,它定義子元素如何分配父元素的剩餘寬度,預設為0,這個時候不索取父元素的寬度。

.item {
  flex-grow: <number>; /* default 0 */
}複製程式碼

如下,給第1個子元素設定 flex-grow 屬性值為1,第2個子元素設定 flex-grow 屬性值為2,則父元素的剩餘寬度會被分成三等分,分別新增給第1個第2個子元素,效果如下:

你真的理解 flex 佈局嗎?

程式碼:

CSS 程式碼:
<style>        
    .box{            
        display: flex;           
        display: -webkit-flex;            
        background: #999;        
    }        
    .box span{            
        margin: 10px 10px;            
        padding: 10px;            
        background: #ff0;            
        width: 50px;        
    }        
    .box span:nth-of-type(1){            
        flex-grow: 1;        
    }        
    .box span:nth-of-type(2){            
        flex-grow: 2;        
    }    
</style>

HTML 程式碼:
<div class="box">        
    <span>love1</span>        
    <span>love2</span>        
    <span>love3</span>        
    <span>love4</span>        
    <span>love5</span>    
</div>
複製程式碼

例如:以上面的為例子,假設父元素的寬度為 1000px ,每個子元素的寬度為100px,則還剩餘500px 的寬度,第1個子元素 flex-grow 值為 1,第2個子元素 flex-grow 值為 2,則會把500px分成三等分,第1個子元素增加500乘以1/3px的寬度,第2個子元素增加500乘以2/3px的寬度


4.3 flex-shrink屬性

flex-shrink 屬性定義了專案的縮小比例,預設為1,即如果空間不足,該專案將縮小。

.item {
  flex-shrink: <number>; /* default 1 */
}複製程式碼

如果所有專案的flex-shrink屬性都為1,當空間不足時,都將等比例縮小。如果一個專案的flex-shrink屬性為0,其他專案都為1,則空間不足時,前者不縮小。

負值對該屬性無效。

4.4 flex-basis 屬性

flex-basis屬性定義了在分配多餘空間之前,專案佔據的主軸空間(main size)。瀏覽器根據這個屬性,計算主軸是否有多餘空間。它的預設值為auto,即專案的本來大小。

.item {
  flex-basis: <length> | auto; /* default auto */
}複製程式碼

它可以設為跟width或height屬性一樣的值(比如350px),則專案將佔據固定空間。

4.5 flex屬性

flex屬性是flex-grow, flex-shrink 和 flex-basis的簡寫,預設值為0 1 auto。後兩個屬性可選。

.item {
  flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}複製程式碼

該屬性有兩個快捷值:auto (1 1 auto) 和 none (0 0 auto)。

建議優先使用這個屬性,而不是單獨寫三個分離的屬性,因為瀏覽器會推算相關值。

4.6 align-self屬性

align-self屬性允許單個專案有與其他專案不一樣的對齊方式,可覆蓋align-items屬性。預設值為auto,表示繼承父元素的align-items屬性,如果沒有父元素,則等同於stretch。

.item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}複製程式碼

該屬性可能取6個值,除了auto,其他都與align-items屬性完全一致。

你真的理解 flex 佈局嗎?

程式碼:

CSS 程式碼:
<style>        
    .box{            
        display: flex;            
        display: -webkit-flex;            
        background: #999;            
        height: 300px;            
        align-items: flex-start;        
    }        
    .box span{            
        margin: 10px 10px;           
        padding: 10px;            
        background: #ff0;        
    }        
    .box span:nth-of-type(3){            
        align-self: flex-end;        
    }    
</style>

HTML 程式碼:
<div class="box">        
    <span>love1</span>        
    <span>love2</span>        
    <span>love3</span>        
    <span>love4</span>        
    <span>love5</span>    
</div>複製程式碼