1. 程式人生 > >CSS3彈性盒子佈局

CSS3彈性盒子佈局

    CSS3中引入的彈性盒子佈局已經有一段時間,也經歷了幾次比較重大的修改,可本人一直都沒怎麼使用過這種佈局,慚愧萬分!這幾天研究了一下這種佈局方式,記錄一下學習筆記,以後日後用到時過來檢視。

名稱:CSS Flexible Box Layout Module Level 1 W3C Candidate Recommendation, 26 May 2016

      本想翻譯過來認真研究一下這篇文件,但發現可愛的WCM官網已經有一篇早期版本的中文版,參考這篇文件也大致可以看懂了。
網址: https://www.w3.org/html/ig/zh/css-flex-1/
名稱:CSS 伸縮盒佈局模組 Editor’s Draft, 16 October 2012

      更重要的是,W3C上說:

This document was produced by the CSS Working Group (part of the Style Activity) as a Candidate Recommendation. This document is intended to become a W3C Recommendation. This document will remain a Candidate Recommendation at least until 1 September 2016 in order to ensure the opportunity for wide review. (引用自:

https://www.w3.org/TR/css-flexbox-1/)

翻譯過來就是說:

本文(指https://www.w3.org/TR/css-flexbox-1/) 的最終目標是要成為W3C的標準。但是至少在2016年9月1日之前,本文還是維持在候選標準(CR)階段,這是為了確保本文件能被廣泛的審查。

      所以,

2016年9月1日,這一天可能是一篇文件成為W3C標準的一天!!!
2016年9月1日,這一天可能是一篇文件成為W3C標準的一天!!!
2016年9月1日,這一天可能是一篇文件成為W3C標準的一天!!!

(重要的事說三遍。當然,本人也會跟蹤這一情況)

      由於本人剛開始學習彈性盒子佈局,自知無法完成一篇通俗易懂的關於彈性盒子佈局應用的文章,故只能通過其他高人的文章來學習,以下三篇是個人感覺寫的通俗易懂的良心之作,特推薦給各位看客,本人以下的部落格內容也主要引用自此,只是部分內容略作修改,特此說明。

CSS3彈性盒佈局是什麼

In the flex layout model, the children of a flex container can be laid out in any direction, and can “flex” their sizes, either growing to fill unused space or shrinking to avoid overflowing the parent. Both horizontal and vertical alignment of the children can be easily manipulated. Nesting of these boxes (horizontal inside vertical, or vertical inside horizontal) can be used to build layouts in two dimensions.

翻譯過來就是:

在彈性盒子佈局中,彈性容器(flex container)中的子元素可以以任意方向排布,也可以伸縮它們自身的尺寸,或者增大自身尺寸以填滿未被使用的空間,或者縮小自身尺寸以避免超出父容器的尺寸範圍。子元素橫向或縱向對齊方式很容易被修改。巢狀的彈性盒子佈局(水平內巢狀垂直,或垂直內巢狀水平),可以用來建立兩個維度上的佈局。

      總結一下什麼是彈性盒子佈局,

彈性盒子佈局的作用——處理頁面佈局
彈性盒子佈局的優點——根據螢幕尺寸或瀏覽器視窗尺寸自動調整頁面中各區域性區域的顯示方式
彈性盒子佈局的相容性——請參見如下網址:http://www.css88.com/book/css/properties/flex/index.htm

彈性盒佈局中的一些專用術語

彈性容器與彈性子項

      一個flexbox佈局是由一個彈性容器(flex container)和彈性子項(flex items)組成,在彈性容器(flex container)中,其所有的子元素都會變成彈性子項(flex items),如下圖:
這裡寫圖片描述

主側軸

這裡寫圖片描述

      main axis:進行佈局時作為佈局基準的軸,在橫向佈局時為水平軸,在縱向佈局時為垂直軸。
      main-start / main-end:進行佈局時的佈局起點與佈局終點。在橫向佈局時為容器的左端與右端,在縱向佈局時為容器的頂端與底端。
      cross axis:與main axis垂直相交的軸,在橫向佈局時為垂直軸,在縱向佈局時為水平軸。
      cross-start / cross-end:cross axis軸的起點與終點。在橫向佈局時為容器的頂端與底端,在縱向佈局時為容器的左端與右端。

將flex-wrap屬性值指定為wrap且進行橫向多行佈局時,按從cross-start到cross-end方向,即從上往下佈局,
將flex-wrap屬性值指定為wrap-reverse且進行橫向多行佈局時,按從cross-end到cross-start方向,即從下往上佈局。

justify-content屬性——規定子元素在主軸方向的對齊方式

   justify-content屬性用於指定如何佈局 彈性盒容器中除子元素之外的,在main axis軸方向(橫向佈局時main axis軸方向為水平方向,縱向佈局時main axis軸方向為垂直方向)上的,剩餘空白部分。

   當flex-grow屬性值不為0時,各子元素在main axis軸方向上自動填滿容器,此時justify-content屬性值無效。

   可指定justify-content屬性值如下所示:
        flex-start:從main-start開始佈局所有子元素(預設值)。
        flex-end:從main-end開始佈局所有子元素。
        center:居中佈局所有子元素。
        space-between:將第一個子元素佈局在main-start處,將最後一個子元素佈局在main-end處,將空白部分平均分配在所有子元素與子元素之間。
        space-around:將空白部分平均分配在以下幾處:main-start與第一個子元素之間、各子元素與子元素之間、最後一個子元素與main-end之間。

    上述各屬性值的區別如下圖所示(灰色代表空白部分)。

這裡寫圖片描述

align-items屬性——規定子元素在側軸方向的對齊方式

     align-items屬性與justify-content屬性類似,但是用於指定彈性盒容器中的各子元素在cross axis軸方向(橫向佈局時cross axis軸方向為垂直方向,縱向佈局時cross axis軸方向為水平方向)上的對齊方式。

      可指定屬性值如下所示。
         flex-start:從cross-start開始佈局所有子元素(預設值)。
         flex-end:從cross-end開始佈局所有子元素。
         center:居中佈局所有子元素。
         baseline:如果子元素的佈局方向與容器的佈局方向不一致,則該值的作用等效於flex-start屬性值的作用。如果子元素的佈局方向與容器的佈局方向保持一致,則所有子元素中的內容沿基線對齊。
         stretch:同一行中的所有子元素高度被調整為最大。如果未指定任何子元素高度,則所有子元素高度被調整為最接近容器高度(當考慮元素邊框及內邊距時,當邊框寬度與內邊距均為0則等於容器高度)。

          上述各屬性值的區別如下圖所示(灰色代表空白部分)。

這裡寫圖片描述

align-self屬性——單獨指定某個子元素在側軸方向的對齊方式

    align-self屬性與align-items屬性的區別在於:align-items被指定為容器元素的樣式屬性,用於指定所有子元素的對齊方式,而align-self屬性被指定為某些子元素的樣式屬性,用於單獨指定這些子元素的對齊方式。例如將容器元素的align-items屬性值指定為center(居中對齊)後,可以將第一個子元素的align-self屬性值指定為flex-start(對齊在cross-start端)。

    可以指定的屬性值如下所示(含義同align-items屬性的各屬性值,此處略):
        auto:繼承父元素的align-items屬性值
        flex-start
        flex-end
        center
        baseline
        stretch

align-content屬性——指定多行在側軸方向上的對齊方式

    當進行多行佈局時,可以使用align-content屬性來指定各行對齊方式。該屬性與align-items屬性的區別在於:align-items屬性用於指定子元素的對齊方式,而align-content屬性用於指定行對齊方式。

    可以指定的屬性值如下所示:
        flex-start:從cross-start開始佈局所有行。
        flex-end:從cross-end開始佈局所有行。
        center:居中佈局所有行。
        space-between:將第一行佈局在cross-start處,將最後一行佈局在cross-end處,將空白部分平均分配在各行之間。
        space-around:將空白部分平均分配在以下幾處:cross-start與第一行之間、各行與行之間、最後一行與cross-end之間。

       
       上述各屬性值的區別如下圖所示(灰色代表空白部分)。

   這裡寫圖片描述

學習彈性盒子佈局的準備工作

      本文將要用到的html文件的emmet結構如下:

div#main>div.content(>section(>h1{section $}+p{文字內容})*4)
            +div.content>section>h1{section 5}
                                +p{文字內容}
                                +(section>h1{section $}+p{文字內容})*3
            +div.content(>section(>h1{section $}+p{文字內容})*4)

      html程式碼如下:

<div id="main">
        <div class="content">
            <section>
                <h1>section 1</h1>
                <p>文字內容</p>
            </section>
            <section>
                <h1>section 2</h1>
                <p>文字內容</p>
            </section>
            <section>
                <h1>section 3</h1>
                <p>文字內容</p>
            </section>
            <section>
                <h1>section 4</h1>
                <p>文字內容</p>
            </section>
        </div>
        <div class="content">
            <section>
                <h1>section 5</h1>
                <p>文字內容</p>
                <section>
                    <h1>section 6</h1>
                    <p>文字內容</p>
                </section>
                <section>
                    <h1>section 7</h1>
                    <p>文字內容</p>
                </section>
                <section>
                    <h1>section 8</h1>
                    <p>文字內容</p>
                </section>
            </section>
        </div>
        <div class="content">
            <section>
                <h1>section 9</h1>
                <p>文字內容</p>
            </section>
            <section>
                <h1>section 10</h1>
                <p>文字內容</p>
            </section>
            <section>
                <h1>section 11</h1>
                <p>文字內容</p>
            </section>
            <section>
                <h1>section 12</h1>
                <p>文字內容</p>
            </section>
        </div>
    </div>

      CSS樣式如下:

      下文出現的所有樣式效果如未做特殊說明,均是在此CSS樣式的基礎上直接新增新樣式而成。

<style>
#main {
    border: 1px dotted #f0f;
    padding: 1em;
}
.content {
    border: 1px dotted #0ff;
    padding: 1em;
}
section {
    border: 1px dotted #f00;
    padding: 1em;
}
</style>

      在瀏覽器中開啟目前為止的示例頁面,頁面中各元素從上往下縱向排列,如下圖所示:
這裡寫圖片描述

display:flex—定義彈性盒子佈局

    對需要彈性佈局的元素的直接父級容器元素使用display:flex;樣式屬性即可。

    在CSS Flexible Box模組中,該容器元素中的每一個子元素均被稱為“Flex item”,將該容器元素稱為“Flex container”。

    彈性盒佈局方式與使用float等樣式屬性進行的佈局方式的一個主要區別為,當使用float等樣式屬性時,需要對容器中每一個元素指定樣式屬性,當使用彈性盒佈局時,只需對容器元素指定樣式屬性即可。

注:

    可能大家也會看到有寫的是display:box/display:flexbox;其實其實他們只是不同時期的規範:

    新規範:2013年最新版本規範的語法 即display:flex/inline-flex;
    中間版本:2011年非官方規範的語法 即display:flexbox/inline-flexbox;
    老規範:2009年規範的語法 即display:box/inline-/box;

      以上述html程式碼為例,我們首先對所有class=content的div元素使用彈性盒佈局,這些div元素的容器元素為id=main的div元素,修改該元素的樣式程式碼如下所示:

#main{
        ...
        display: flex;
        ...
}

      頁面效果如下圖:
這裡寫圖片描述

flex-direction—設定容器中所有子元素的排列方向

    通過使用flex-direction樣式屬性,來控制容器中所有子元素的排列方向,可指定值如下所示。

    row:橫向排列(預設值)
    row-reverse:橫向反向排列
    column:縱向排列
    column-reverse:縱向反向排列

      為id=main的div元素的新增如下樣式程式碼:

#main{
        ...
        display: flex;
        flex-direction: row-reverse;
        ...
    }

      開啟頁面可見,所有class=content的div元素的排列方式被修改為從容器元素(即id=main的div元素)的右端開始橫向反向排列,如下圖所示
這裡寫圖片描述

利用巢狀彈性盒子佈局實現兩個維度上的佈局

      接下來,我們為父級元素和子元素都設定彈性盒子佈局,檢視一下巢狀彈性盒子佈局,首先在id=main的div元素設定彈性盒子佈局,程式碼如下:

#main{
        ...
        display: flex;
        ...
}

      接著,我們對所有class=content的div元素設定彈性盒子佈局並指定flex-direction: column-reverse;樣式屬性,程式碼如下所示:

.content {
    display: flex;
    flex-direction: column-reverse;
}

      在瀏覽器中開啟示例頁面,頁面中所有class=content的div元素的所有section子元素的排列方式被修改為縱向反向排列(section子元素中的section孫元素的排列方式不受影響,如section6、7、8),如下圖所示。
 這裡寫圖片描述

order—改變容器中各子元素的顯示順序

      使用彈性盒子佈局時,可以通過order屬性來改變容器中各子元素的顯示順序。可以在每個子元素的樣式中加入order屬性,該屬性使用一個表示序號的整數屬性值(可以為負數),瀏覽器在顯示的時候根據該序號從小到大來顯示容器中的這些子元素。

      通過將所有class=content的div元素中的第2個section子元素的order屬性設定為order:-1,將這些section子元素被優先顯示在其他section子元素之前,程式碼如下所示:

 .content {
        display: flex;
        flex-direction: column;
    }
    .content section:nth-child(2) {
        order: -1;
    }

      在瀏覽器中開啟示例頁面,頁面中所有class=content的div元素中的第2個section子元素(secton2、10)被顯示在其他section子元素之前,如下圖所示。
這裡寫圖片描述

設定元素寬度及高度

      接下來首先介紹如何設定被橫向排列的每一個元素的寬度。

使用flex屬性使所有子元素的總寬度等於容器寬度

通過將所有class=content的div元素的flex屬性值設定為1,使所有class=content的div元素的總寬度等於容器元素,即id=main的div元素的寬度,程式碼如下所示。
當所有class=content的div元素的flex屬性值都被設定為1時,這些div元素的寬度均等。
#main {
            ...
            display: flex;
        }
    .content {
        ...
        flex:1;
    }

      在瀏覽器中開啟示例頁面,所有class=content的div元素的寬度自動增長,這些元素的總寬度等於容器元素,即id=main的div元素的寬度,每一個class=content的div元素的寬度均等,如下圖所示。
這裡寫圖片描述

      接下來,我們設定第二個樣式類名為content的div元素的flex屬性值為2,程式碼如下所示。

#main {
            ...
            display: flex;
        }
    .content {
        ...
        flex:1;
    }
    .content:nth-child(2) {
        flex:2;
    }

      頁面效果如下圖:
這裡寫圖片描述

      為了更清晰地計算元素寬度,我們取消所有元素的邊框設定及內邊距設定,修改後的完整樣式程式碼如下所示。

<style>
    #main {
        display: flex;
    }
    .content {
        display: flex;
        flex-direction: column;
        flex:1;
    }
    .content:nth-child(2) {
        flex:2;
    }
    </style>

      在瀏覽器中開啟示例頁面如下圖所示,第二個class=content的div元素寬度為其他class=content的div元素寬度的兩倍,假設這些元素的容器元素,即id=main的div元素的寬度等於600px,則第一個與第三個class=content的div元素寬度的寬度均等於150px,第二個class=content的div元素寬度的寬度等於300px。
這裡寫圖片描述

使用flex-grow屬性來指定元素寬度

除了flex可以指定元素寬度,也可以使用flex-grow屬性來指定元素寬度,但是該樣式屬性對於元素寬度的計算方法與flex樣式屬性對於元素寬度的計算方法有所不同。

      接下來指定所有class=content的div元素的flex-grow樣式屬性值為1,寬度為150px,指定第二個樣式class=content的div元素的flex-grow樣式屬性值為為3。修改後的完整樣式程式碼如下所示。

<style>
        #main {
            display: flex;
        }
        .content {
            display: flex;
            flex-direction: column;
            width:150px;
            flex-grow:1;
        }
        .content section:nth-child(2) {
            order: -1;
        }
        .content:nth-child(2) {
            flex-grow:3;
        }
    </style>

      在瀏覽器中開啟示例頁面,假設這些元素的容器元素,即id屬性值為main的div元素的寬度等於600,則第一個與第三個樣式類名為content的div元素寬度的寬度均等於180px,第二個樣式類名為content的div元素寬度的寬度等於240px。對於每個樣式類名為content的div元素寬度的計算步驟如下所示:

    600(容器寬度)-150*3(三個樣式類名為content的div元素寬度的總寬度)=150
    150/5(三個樣式類名為content的div元素寬度的flex-grow樣式屬性值的總和=1+1+3=5)=30
    第一個與第三個樣式類名為content的div元素寬度的寬度均等於150(其width樣式屬性值+)+30*1(其flew-grow樣式屬性值)=180px
    第二個樣式類名為content的div元素寬度的寬度等於150(其width樣式屬性值+)+30*3(其flew-grow樣式屬性值)=240px

使用flex-shrink屬性來指定元素寬度

      使用flex-shrink屬性來指定元素寬度,該樣式屬性與flex-grow樣式屬性的區別在於:
      當子元素的width樣式屬性值的總和小於容器元素的寬度值時,必須通過flex-grow樣式屬性來調整子元素寬度,
      當子元素的width樣式屬性值的總和大於容器元素的寬度值時,必須通過flex-shrink樣式屬性來調整子元素寬度。

      接下來指定所有class=content的div元素的flex-shrink樣式屬性值為1,寬度為250px, 指定第二個class=content的div元素的flex-shrink樣式屬性值為為3。修改後的完整樣式程式碼如下所示。

<style>
        #main {
            display: flex;
        }
        .content {
            display: flex;
            flex-direction: column;
            width:250px;
            flex-shrink:1;
        }
        .content section:nth-child(2) {
            order: -1;
        }
        .content:nth-child(2) {
            flex-shrink:3;
        }
    </style>

      在瀏覽器中開啟示例頁面,假設這些元素的容器元素,即id屬性值為main的div元素的寬度等於600,則第一個與第三個樣式類名為content的div元素寬度的寬度均等於220px,第二個樣式類名為content的div元素寬度的寬度等於160px。對於每個樣式類名為content的div元素寬度的計算步驟如下所示:

    250*3(三個樣式類名為content的div元素寬度的總寬度)-600(容器寬度)=150
    150/5(三個樣式類名為content的div元素寬度的flex-shrink樣式屬性值的總和=1+1+3=5)=30
    第一個與第三個樣式類名為content的div元素寬度的寬度均等於250(其width樣式屬性值+)-30*1(其flew-shrink樣式屬性值)=220px
    第二個樣式類名為content的div元素寬度的寬度等於250(其width樣式屬性值+)-30*3(其flew-grow樣式屬性值)=160px

使用flex-basis屬性來指定元素寬度

      在使用flex-grow樣式屬性或flex-shrink樣式屬性調整子元素寬度時,也可以使用flex-basis樣式屬性指定調整前的子元素寬度,該樣式屬性與width樣式屬性的作用完全相同。

將flex-grow、flex-shrink以及flex-basis樣式屬性值合併寫入flex樣式屬性中

      可以將flex-grow、flex-shrink以及flex-basis樣式屬性值合併寫入flex樣式屬性中,方法如下所示。

    flex:flex-grow樣式屬性值 flex-shrink樣式屬性值 flex-basis樣式屬性值;

      在使用flex樣式屬性值時,flex-grow、flex-shrink以及flex-basis樣式屬性值均為可選用樣式屬性值,當不指定flex-grow、flex-shrink樣式屬性值時,預設樣式屬性值均為1,當不指定flex-basis樣式屬性值時,預設樣式屬性值為0px。

      修改本示例中的樣式程式碼如下所示:

<style>
    #main {
        display: flex;
    }
    .content {
        display: flex;
        flex-direction: column;
        width:250px;
        flex:250px;
    }
    .content section:nth-child(2) {
        order: -1;
    }
    .content:nth-child(2) {
        flex:1 3 250px;
    }
    </style>

      在瀏覽器中開啟示例頁面,假設這些元素的容器元素,即id屬性值為main的div元素的寬度等於600,則第一個與第三個樣式類名為content的div元素寬度的寬度均等於220px,第二個樣式類名為content的div元素寬度的寬度等於160px。

  在子元素為橫向排列時,flex、flex-grow、flex-shrink以及flex-basis樣式屬性均用於指定或調整子元素寬度,
   當子元素為縱向排列時,flex、flex-grow、flex-shrink以及flex-basis樣式屬性均用於指定或調整子元素高度。

單行佈局與多行佈局

      可以使用flex-wrap樣式屬性來指定單行佈局或多行佈局,可指定樣式屬性值如下所示:

    nowrap:不換行
    wrap:換行
    wrap-reverse:雖然換行,但是換行方向與使用wrap樣式屬性值時的換行方向相反

      接下來首先恢復頁面內各div元素的邊框與內邊距(padding)的指定,同時指定所有樣式類名為content的div元素的寬度為250px,程式碼如下所示。

<style>
    #main {
        border: 1px dotted #f0f;
        padding: 1em;
        display: flex;
    }
    .content {
        border: 1px dotted #0ff;
        padding: 1em;
        display: flex;
        flex-direction: column;
        flex:250px;
    }
    section {
        border: 1px dotted #f00;
        padding: 1em;
    }
    .content section:nth-child(2) {
        order: -1;
    }
    </style>

      然後指定容器元素,即id屬性值為main的div元素的flex-wrap樣式屬性值為wrap,以指定允許對所有樣式類名為content的div元素進行換行佈局,程式碼如下所示。

#main {
        flex-wrap: wrap;
    }

      在瀏覽器中開啟示例頁面,當瀏覽器視窗寬度不足以容納三個樣式類名為content的div元素時,最右邊的樣式類名為content的div元素被換行顯示,如下圖所示。
這裡寫圖片描述

總結

1、要對元素使用彈性盒子佈局,只要在其直接父級容器元素上設定display:flex即可
2、以下7個屬性是加在flex container上的:
      display:flex/inline-flex;
      flex-direction
      flex-wrap
      flex-flow
      justify-content
      align-items
      align-content
3、這6個屬性是加在flex item上的
      order
      flex-grow
      flex-shrink
      flex-basis
      flex
      align-self
4、可以將flex-direction樣式屬性值與flex-wrap樣式屬性值合併書寫在flex-flow樣式屬性中。以下兩段程式碼的作用完全相同。

    //使用flex-direction樣式屬性與flex-wrap樣式屬性
    .content {
        flex-direction: row;
        flex-wrap: wrap;
    }
    //使用flex-flow樣式屬性
    .content {
        flex-flow: row wrap;
    }