Flex 佈局相關用法

前言:css

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

2009年,W3C提出了一種新的方案----Flex佈局,能夠簡便、完整、響應式地實現各類頁面佈局,2012年獲得進一步完善。web

2009年版本的語法已通過時(display: box),使用的時候爲了兼容須要加上一些前綴瀏覽器

/* 形如: */
    display: -webkit-box; /* Chrome 4+, Safari 3.1, iOS Safari 3.2+ */
    display: -moz-box; /* Firefox 17- */
    display: -webkit-flex; /* Chrome 21+, Safari 6.1+, iOS Safari 7+, Opera 15/16 */
    display: -moz-flex; /* Firefox 18+ */
    display: -ms-flexbox; /* IE 10 */
    display: flex; /* Chrome 29+, Firefox 22+, IE 11+, Opera 12.1/17/18, Android 4.4+ */

因此仍是建議使用新版形式ide

2012年將是日後標準的語法(display: flex),大部分瀏覽器已經實現了無前綴版本。佈局

 

囉嗦那麼多,正式開始flex

 

 

1、Flex 是什麼,爲何要用?

就 W3C 官方給到的解釋是,這是設計來實現更復雜的版面佈局。ui

那我本身對他的定義是,Flexbox 從本質上就是一個 Box-model 的延伸,咱們都知道 Box-model 定義了一個元素的盒模型,然而 Flexbox 更進一步的去規範了這些盒模型之間彼此的相對關係。而不須要去用一些很 cheat 的作法,去 hack 一些原本其實不該該用來作版面佈局的屬性。flexbox

Flex佈局主要思想是讓容器有能力讓其子項目可以改變其寬度、高度(甚至順序),以最佳方式填充可用空間(主要是爲了適應全部類型的顯示設備和屏幕大小)。Flex容器會使子項目(伸縮項目)擴展來填滿可用空間,或縮小他們以防止溢出容器。spa

最重要的是,Flexbox佈局方向不可預知,他不像常規的佈局(塊就是從上到下,內聯就從左到右)。而那些常規的適合頁面佈局,但對於支持大型或者雜的應用程序(特別是當他涉及到取向改變、縮放、拉伸和收縮等)就缺少靈活性。

圍繞着三個主要問題,來了解Flex佈局

1. 這能作什麼?也就是他能解決什麼問題?
2. 能用在哪裡?在哪些地方能用這個方法?
3. 爲何能用?他實現所用到的邏輯是什麼?

固然了,這仨問題也直接貫穿在功能實現當中,因此仍是來了解使用的方式。

 

2、Flex的基本概念

由於Flex佈局是相對模塊而言,而不是一個屬性,它涉及不少東西,包括其整個組屬性。他們當中一部分是容器(父元素,稱爲「伸縮容器」container),另外一部分是子元素(稱爲「伸縮項目」 flex item)。

常規佈局是基於塊和內聯流方向,而Flex佈局是基於flex-flow流。這張圖,解釋了flex佈局的主要思想。

容器默認存在兩根軸:水平的主軸(main axis)和垂直的交叉軸(cross axis)。

主軸的開始位置(與邊框的交叉點)叫作main start,結束位置叫作main end;交叉軸的開始位置叫作cross start,結束位置叫作cross end。

項目默認沿主軸排列。單個項目佔據的主軸空間叫作main size,佔據的交叉軸空間叫作cross size。

 

3、Flex 的使用方法

跟常規佈局操做同樣,flex也是基於css屬性的設置來實現。

如上圖所示,主要包括 設置父容器的屬性 和 設置子項目的屬性(若是又有內嵌的容器那就同理)

 

(1)父容器的屬性

1.display:flex | inline-flex;(適用於父容器)

這個是用來定義伸縮容器,是內聯仍是塊取決於設置的值。這個時候,他的全部子元素將變成flex文檔流,稱爲伸縮項目。

display: other values | flex | inline-flex;    

若是是Webkit內核的瀏覽器,必須加上-webkit前綴。好比:

display: -webkit-flex;

但有兩點要注意的是,父容器設置flex以後:

  •  CSS的columns在伸縮容器上沒有效果。
  •  float、clear和vertical-align在子項目上沒有效果。

 

2.flex-direction(適用於父容器)

flex-direction屬性決定主軸的方向(即項目的排列方向)。

flex-direction: row | row-reverse | column | column-reverse    
  •  row(默認值):在「ltr」排版方式下從左向右排列;在「rtl」排版方式下從右向左排列。
  •  row-reverse:與row排列方向相反,在「ltr」排版方式下從右向左排列;在「rtl」排版方式下從左向右排列。
  •  column:相似 於row,不過是從上到下排列
  •  column-reverse:相似於row-reverse,不過是從下到上排列。

注:

主軸起點與主軸終點方向分別等同於當前書寫模式的始與結方向。

其中「ltr」所指文本書寫方式是「left-to-right」也就是從左向右書寫;

而「rtl」所指的恰好與「ltr」方式相反,其書寫方式是「right-to-left」,也就是從右向左書寫

那不如來個例子:

如今有一個父容器div,其中有5個子項目div.

爲了保證效果展現,父容器暫設width: 40%; min-height: 250px; 子項目分別設置不一樣寬 width: 10%|15%|20%; 高度暫設固定高度30px(但設置高度會時stretch失效)

基本代碼爲:(後續例子都是基於這個展開,變更的部分爲關鍵的各 flex屬性)

    <div class="box">
        <div class="item item1 center">item1</div>
        <div class="item item2 center">item2</div>
        <div class="item item3 center">item3</div>
        <div class="item item4 center">item4</div>
        <div class="item item5 center">item5</div>
    </div>
<style type="text/css">
    html,body,div {margin: 0;padding: 0}
    .center { 
        padding-top: 5px;
        text-align: center;
        background: #abc;
        font: bold 14px/1.2em Arial, Helvetica, sans-serif ;
        color: #fff;
    }
    .item { 
        border: 2px solid #0f0;
    }

    .item1 { 
        width: 10%;
        height: 30px;
    }
    .item2 { 
        width: 10%;
        height: 30px;
    }
    .item3 { 
        width: 15%;
        height: 30px;
    }
    .item4 { 
        width: 15%;
        height: 30px;
    }
    .item5 { 
        width: 25%;
        height: 30px;
    }

    .box { 
        display: flex;
        display: -webkit-flex;
        flex-direction: row;

        margin: 10px auto;
        width: 40%;
        min-height: 250px;
        overflow: hidden;
        border: 2px solid #0cf;
    }
</style>

更新flex-direction的值,row | row-reverse | column | column-reverse 順序變化

 

3.flex-wrap(適用於父容器)

這個主要用來定義伸縮容器裏是單行仍是多行顯示,側軸的方向決定了新行堆放的方向。

flex-wrap: nowrap | wrap | wrap-reverse    
  • nowrap(默認值):伸縮容器單行顯示,「ltr」排版下,伸縮項目從左到右排列;「rtl」排版上伸縮項目從右向左排列。
  •  wrap:伸縮容器多行顯示,「ltr」排版下,伸縮項目從左到右排列;「rtl」排版上伸縮項目從右向左排列。
  •  wrap-reverse:伸縮容器多行顯示,「ltr」排版下,伸縮項目從右向左排列;「rtl」排版下,伸縮項目從左到右排列。(和wrap相反)

爲了看到wrap效果,先增大子項目寬度

.item1 { 
        width: 40%;
        height: 30px;
    }
    .item2 { 
        width: 40%;
        height: 30px;
    }
    .item3 { 
        width: 60%;
        height: 30px;
    }
    .item4 {
        width: 60%;
        height: 30px;
    }
    .item5 { 
        width: 80%;
        height: 30px;
    }

    .box { 
        display: flex;
        display: -webkit-flex;
        flex-direction: row;
        flex-wrap: nowrap;

        margin: 10px auto;
        width: 40%;
        min-height: 250px;
        overflow: hidden;
        border: 2px solid #0cf;
    }

更新flex-wrap的值,nowrap| wrap| wrap-reverse 順序變化

 

4.flex-flow(適用於父容器)

這個是「flex-direction」和「flex-wrap」屬性的縮寫版本。同時定義了伸縮容器的主軸和側軸。其默認值爲「row nowrap」。

flex-flow: <‘flex-direction’> || <‘flex-wrap’>

好比 column nowrap  和 column wrap-reverse

    .box { 
        display: flex;
        display: -webkit-flex;
        flex-flow: column nowrap;
        ...
         }

 

5.justify-content(適用於父容器)

這個是用來定義伸縮項目沿着主軸線的對齊方式。當一行上的全部伸縮項目都不能伸縮或可伸縮可是已經達到其最大長度時,這一屬性纔會對多餘的空間進行分配。當項目溢出某一行時,這一屬性也會在項目的對齊上施加一些控制。

justify-content: flex-start | flex-end | center | space-between | space-around    
  •  flex-start(默認值):伸縮項目向一行的起始位置靠齊。
  •  flex-end:伸縮項目向一行的結束位置靠齊。
  •  center:伸縮項目向一行的中間位置靠齊。
  •  space-between:伸縮項目會平均地分佈在行裏。第一個伸縮項目一行中的最開始位置,最後一個伸縮項目在一行中最終點位置,項目之間的間隔都相等。
  •  space-around:伸縮項目會平均地分佈在行裏,每一個項目兩側的間隔相等。因此,項目之間的間隔比項目與邊框的間隔大一倍。

這會兒先把子項目的寬度恢復咯

.item1 { 
        width: 10%;
        height: 30px;
    }
    .item2 { 
        width: 10%;
        height: 30px;
    }
    .item3 { 
        width: 15%;
        height: 30px;
    }
    .item4 {
        width: 15%;
        height: 30px;
    }
    .item5 { 
        width: 25%;
        height: 30px;
    }

    .box { 
        display: flex;
        display: -webkit-flex;
        flex-direction: row;
        justify-content: flex-start;
        ...
    }

按順序 更新 justfy-content

direction爲row是這樣,爲column同理,自行聯想吧

6.align-items(適用於父容器)

這個主要用來定義伸縮項目能夠在伸縮容器的當前行的側軸上對齊方式。能夠把他想像成側軸(垂直於主軸)的「justify-content」。

align-items: flex-start | flex-end | center | baseline | stretch
  •  flex-start:伸縮項目在側軸起點邊的外邊距緊靠住該行在側軸起始的邊。
  •  flex-end:伸縮項目在側軸終點邊的外邊距靠住該行在側軸終點的邊 。
  •  center:伸縮項目的外邊距盒在該行的側軸上居中放置。
  •  baseline:伸縮項目根據他們的基線對齊。
  •  stretch(默認值):伸縮項目拉伸填充整個伸縮容器。若是項目未設置高度或設爲auto,將佔滿整個容器的高度

stretch的使用受到高度的影響,因此可先把item1-3-5取消高度的設置

.item1 { 
        width: 10%;
        /* height: 30px; */
    }
    .item2 { 
        width: 10%;
        height: 30px;
    }
    .item3 { 
        width: 15%;
        /* height: 30px; */
    }
    .item4 {
        width: 15%;
        height: 30px;
    }
    .item5 { 
        width: 25%;
        /* height: 30px; */
    }

    .box { 
        display: flex;
        display: -webkit-flex;
        align-items: flex-start;
        ...
    }

按順序更新 align-items

 

7.align-content(適用於父容器)

這個屬性主要用來調準伸縮行在伸縮容器裏的對齊方式。相似於伸縮項目在主軸上使用「justify-content」同樣。

注:請注意本屬性在只有一行的伸縮容器上沒有效果。

align-content: flex-start | flex-end | center | space-between | space-around | stretch    
  •  flex-start:各行向伸縮容器的起點位置堆疊。
  •  flex-end:各行向伸縮容器的結束位置堆疊。
  •  center:各行向伸縮容器的中間位置堆疊。
  •  space-between:各行在伸縮容器中平均分佈。
  •  space-around:各行在伸縮容器中平均分佈,在兩邊各有一半的空間。
  •  stretch(默認值):各行將會伸展以佔用剩餘的空間。

由於只有一行的伸縮容器看不到效果,那就再把子項目的寬度改回來先,讓它換行知足多行的條件

.item1 { 
        width: 40%;
         height: 30px; 
    }
    .item2 { 
        width: 40%;
        height: 30px;
    }
    .item3 { 
        width: 60%;
         height: 30px; 
    }
    .item4 {
        width: 60%;
        height: 30px;
    }
    .item5 { 
        width: 80%;
         height: 30px; 
    }

    .box { 
        display: flex;
        display: -webkit-flex;
        flex-wrap: wrap;
        align-content: flex-start;
        ...
    }

則按順序更新 align-content

 

 

(2)子項目的屬性

1.order(適用於子項目)

order屬性定義項目的排列順序。數值越小,排列越靠前,默認爲0。

order: <integer>

先將各子項目寬度恢復爲小值,設置item5的order值爲 -1 ,item2 的爲1

.item1 { 
        width: 10%;
         height: 30px; 
    }
    .item2 { 
        width: 10%;
        height: 30px;
        order: 1;
    }
    .item3 { 
        width: 15%;
         height: 30px; 
    }
    .item4 {
        width: 15%;
        height: 30px;
    }
    .item5 { 
        width: 25%;
        height: 30px; 
        order: -1;
    }

    .box { 
        display: flex;
        display: -webkit-flex;
        flex-direction: row;
                ...
        }

改變 direction  row | column 可看到

 

2.flex-grow(適用於子項目)

根據須要用來定義伸縮項目的擴展能力。它接受一個不帶單位的值作爲一個比例。主要用來決定伸縮容器剩餘空間按比例應擴展多少空間。

若是全部伸縮項目的「flex-grow」設置了「1」,那麼每一個伸縮項目將設置爲一個大小相等的剩餘空間。若是你給其中一個伸縮項目設置了「flex-grow」值爲「2」,那麼這個伸縮項目所佔的剩餘空間是其餘伸縮項目所佔剩餘空間的兩倍。負值無效。

flex-grow: <number> (默認值爲: 0 即若是存在剩餘空間,也不放大。)

暫去掉子項目的order屬性,咱們先來看看初始時 和 加了 flex-grow後(item1 設爲1,item2設爲2)的區別

當direction爲row時,將剩餘空間吃透

當direction爲column 時,將剩餘空間吃透

3.flex-shrink(適用於子項目)

根據須要用來定義伸縮項目收縮的能力。負值無效。

flex-shrink: <number> (默認值爲: 1 即若是空間不足,該項目將縮小。)    

好了,又有機會把子項目寬度設大了。默認 shrink值爲1, 爲0則不縮小,數字更大則縮小程度更大

.item1 { 
        width: 40%;
        height: 30px; 
        flex-shrink: 1;
    }
    .item2 { 
        width: 40%;
        height: 30px;
    }
    .item3 { 
        width: 60%;
        height: 30px; 
        flex-shrink: 1;
    }
    .item4 {
        width: 60%;
        height: 30px;
    }
    .item5 { 
        width: 80%;
        height: 30px; 
        flex-shrink: 1;
    }

如今shrink值都爲1,把item1值設爲0不縮小,item3值設爲3,item5值設爲5 看看變化

 

4.flex-basis(適用於子項目)

flex-basis屬性定義了在分配多餘空間以前,項目佔據的主軸空間(main size)。

瀏覽器根據這個屬性,計算主軸是否有多餘空間。它的默認值爲auto,即項目的原本大小。 負值無效。

flex-basis: <length> | auto (默認值爲: auto)    

好比對於item1,設置其basis爲100px,加上它的邊框總width爲104px ,計算後發現主軸還有剩餘空間,則按必定規則計算伸展的長度

.item1 { 
        width: 10%;
        height: 30px; 
        flex-basis: 100px;
        flex-grow: 1;
    }

 

5.flex(適用於子項目)

這是「flex-grow」、「flex-shrink」和「flex-basis」三個屬性的縮寫。其中第二個和第三個參數(flex-shrink、flex-basis)是可選參數。默認值爲「0 1 auto」。

flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]    

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

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

 

6.align-self(適用於子項目)

align-self屬性容許單個項目有與其餘項目不同的對齊方式,可覆蓋align-items屬性。

默認值爲auto,表示繼承父元素的align-items屬性,若是沒有父元素,則等同於stretch。

align-self: auto | flex-start | flex-end | center | baseline | stretch
.item1 { 
        width: 10%;
        height: 30px; 
        align-self: flex-start;
    }
    .item2 { 
        width: 10%;
        height: 30px;
        align-self: flex-end;
    }
    .item3 { 
        width: 15%;
        height: 30px; 
        align-self: center;
    }
    .item4 {
        width: 15%;
        height: 30px;
        align-self: baseline;
    }
    .item5 { 
        width: 25%;
        height: 30px; 
        align-self: stretch;
    }

初始樣式和加了 align-self的對比

 

4、grow  shrink 的計算規則

能夠看到,各子項目擴張收縮的程度是不一樣的,那麼它們是怎麼計算的呢?

flex-grow 計算的原理是跟flex  flex-basis屬性有關的,flex-shrink 的計算原理也和flex-basis有關

先來了解flex-basis ,這個屬性在 flex 容器爲橫向的時候,其實就是寬度,當咱們把 item 指定成 flex: 0 0 480px 時,其實就是把它的寬度設定成 480px。

flex-basis屬性 它的默認值爲auto,即項目的原本大小

好來看看是怎麼計算的

1.先來看看grow

grow 表示在 item 總寬度比容器小的時候,爲了讓 item 填滿容器,每一個 item 增長的寬度。

假設有三個 basis 爲 100px 的 item。

咱們從左到右給予 grow 值分別爲 三、二、1,那麼當 flex 做用以後,最左邊的 item 實際增長的寬度是多少?

從圖中能夠算到增長的寬度是 90px,因而最後最左邊 item 的寬度是 190px。

 

2.再來看看 shrink 

grow 跟 shrink 實際上是雙胞胎,其實很像

shrink 表示在 item 總寬度比容器大的時候,爲了讓 item 填滿容器,每一個 item 減小的寬度。

可是計算的公式倒是不同的。爲何?

由於當你在加的時候無所謂,可是在減的時候,若是隻計算賦予的 shrink 值,那麼頗有可能最後減小的寬度比 basis 大,因而 item 的寬度就變成負值。

那咱們該怎麼修正?

把 basis 當成參數計算進去,這樣就能保證減小的寬度永遠小於 basis。

因此咱們能夠獲得修正後的公式,同樣以最左邊爲例子,最後計算出來減小 60px,因而 item 就變成 140px。

以上腦子很差使,不要緊,實際上最經常使用的只是 flex: 1。

 

後記:

固然,知道屬性的用法還不夠,還須要更多的實例練習來掌握,Flex 佈局教程:實例篇

延伸閱讀

相關文章
相關標籤/搜索