Flex 布局相關用法


前言:

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

2009年,W3C提出了一種新的方案----Flex布局,可以簡便、完整、響應式地實現各種頁面布局,2012年得到進一步完善。

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+ */

所以還是建議使用新版形式

2012年將是往后標准的語法(display: flex),大部分瀏覽器已經實現了無前綴版本。

 

啰嗦那么多,正式開始

 

 

一、Flex 是什么,為什么要用?

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

那我自己對他的定義是,Flexbox 從本質上就是一個 Box-model 的延伸,我們都知道 Box-model 定義了一個元素的盒模型,然而 Flexbox 更進一步的去規范了這些盒模型之間彼此的相對關系。而不需要去用一些很 cheat 的做法,去 hack 一些本來其實不應該用來做版面布局的屬性。

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

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

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

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

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

 

二、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。

 

三、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的對比

 

四、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 值分別為 3、2、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 布局教程:實例篇

延伸閱讀

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM