[譯]當咱們在使用 display: flex 的時候,到底發生了什麼?

原文:What Happens When You Create A Flexbox Flex Container?,by Rachel Andrewcss

按我想法的話,CSS 網格佈局(grid)和彈性佈局(Flexbox)應該同時出現纔對,這樣網頁佈局方案就變得完整了。事實是,彈性佈局先出現,由於使用彈性佈局建立類網格(grid-type)系統比使用浮動更加便捷,因而咱們便獲得了許多基於 Flexbox 的網格系統。實際上,Flexbox 的優點並非用來建立網格系統,這也是爲何有時咱們在用它建立網格系統時,感受很費勁的緣由。算法

我準備開一個小系列的文章,花點時間解密一下 Flexbox——就像過去我在講解 Grid 同樣。咱們將看到 Flexbox 的設計目的,它真正作得好的地方,以及爲何咱們不選擇它做爲佈局方法。本文中將會介紹當咱們在使用 display: flex 的時候,到底發生了什麼?app

Flex 容器

爲了使用彈性佈局,咱們須要先有一個元素充當 Flex 容器的角色。容器使用 display: flex 聲明:ide

📷See the Pen Smashing Flexbox Series 1: display: flex; by Rachel Andrew佈局

display: flex 到底作了什麼呢?在 Display Module Level 3 規範中,定義每 display 屬性值由兩部分組成:內部顯示模型(inner display model)和外部顯示模型(outer display model)。咱們使用 display: flex 的時候,實際定義的是 display: block flex。Flex 容器的外部顯示類型是 block,在文檔流(normal flow)中表現爲塊級元素(block level element),內部顯示類型是 flex,因此容器的直接子元素將參與彈性佈局。flex

固然,咱們還可使用 display: inline-flex 定義 Flex 容器,與上面聲明相似,它實際定義的是 display: inline flex。Flex 容器表現的像個行內元素,其直接子元素將參與彈性佈局。ui

📷See the Pen Smashing Flexbox Series 1: display: inline-flex; by Rachel Andrewflexbox

理解了元素的外部顯示模型和內部顯示模型,對理解元素及其子元素在頁面中的表現行爲很是有幫助。你能夠將這種思路帶入到任意其餘類型的盒子中:這個元素的表現特徵爲什麼?它的子元素呢?答案是跟外部顯示模型和內部顯示模型有關。spa

行與列

定義好 Flex 容器後,一些初始值就開始起做用了。在咱們沒有設置任何其餘屬性的狀況下,全部的 Flex 項目 會排列爲一行。之因此如此,是由於 flex-direction 的初始值是 row設計

flex-direction 屬性設置的是主軸(main axis)的方向,取值除了 row 以外,還包括:

  • column
  • row-reverse
  • column-reverse

這些排列在一行的 Flex 項目,始於內聯維度(inline dimension)的起始邊緣(start edge)、按照在源碼中出現的結構順序,依次排列。在規範中,這個「起始邊緣」被稱爲 main-start

main-start 位於內聯維度的起始端

若是使用的是 column,則 Flex 項目從塊維度(block dimension)起始邊緣開始排列,從而造成一列。

main-start 位於塊維度的起始端

若是使用的是 row-reverse,則 main-startmain-end 的位置就調換了。所以,Flex 項目會一個個按照與以前相反的順序排列。

main-start 位於內聯維度的終端

column-reverse 的做用於此相似。須要知道的是,這些值沒有「改變 Flex 項目的順序」,順序變了只是表徵而已,改變的實際上是 Flex 項目從哪開始佈局,也就是說改變的是 main-start 的位置。所以,Flex 項目按照反序顯示,由於它們是沿着容器 的另外一邊開始佈局的。

還有一個比較重要的點,就是 Flex 項目的排列順序上的不一樣只是純視覺上的。咱們只是要求 Flex 項目從結束邊緣(end edge)開始顯示,對於屏幕閱讀器(screen reader)或是當你按 Tab 鍵切換元素的時候,結果順序仍是在源碼中出現的順序。

上面多此重複按下 Tab 鍵,能夠觀察按鈕被 focus 的順序與在源碼中出現的順序同樣,與顯示順序無關。

Flexbox 中的兩根軸

咱們已經講了彈性佈局裏一個很是重要的特性:主軸方向能從行切換到列。理解這種軸切換,能使咱們更好地理解網格佈局中對齊的工做原理。網格屬於二維佈局,咱們幾乎可使用在彈性佈局中一樣的方式設置 Grid 項目在兩個軸上的對齊效果。

咱們已經解釋了主軸,也就是 flex-direction 屬性值定義的那個方向。交差軸(cross axis)是另外一個維度。若是你設置了 flex-direction: row,主軸是沿着行的,而交差軸沿着列向下。若是設置的是 flex-direction: column,則主軸沿着列向下,而交差軸則沿着行。這就是咱們要介紹的彈性佈局的另外一個重要特性,兩個軸的方向與屏幕的物理 維度沒有關係,咱們沒有討論從左到右的行,或從上到下的列,是由於狀況並不是老是如此。

書寫模式

上面在講行和列的時候,提到了內聯和塊維度。本文使用英文書寫的,是水平書寫格式(譯註:原文是英文,不過如今中文書寫格式也與英文同樣)。也就是當你爲 Flexbox 指定爲 row 排列方式的話,會獲得水平排列的 Flex 項目。這種狀況下,main-start 在左邊——也就是英文句子開始的地方。

像在阿拉伯這樣的語言方向從右向左的國家,那麼起始邊緣始於右邊。

See the Pen Smashing Smashing Flexbox Series 1: row with rtl text by Rachel Andrew

當我只是建立了一個 Flex 容器的時候,Flexbox 的初始值代表 Flex 項目從右邊開始,向左排列顯示。內聯方向(inline direction)的起始邊緣就是咱們使用的書寫模式下句子開始的地方。

垂直書寫模式(vertical writing mode)下的行是垂直的,由於在垂直語言環境下行就是垂直的,文本也是垂直顯示的。咱們在 Flex 容器上設置 writing-mode: vertical-lr 就能看到效果。這時候,當你設置 flex-directionrow 的時候,就能看到在垂直方向上顯示的 Flex 項目。

See the Pen Smashing Smashing Flexbox Series 1: row with a vertical writing mode by Rachel Andrew

所以,行能夠是水平顯示,main-start 在左邊或右邊,固然也能夠是垂直的,main-start 在頂部。當你習慣於水平排列思惟,看到垂直書寫模式下設置了 flex-direction: row 的 Flex 容器中的項目 是垂直排列的,可能感受很奇怪,不過人家確實是在行的方向上排列的。

要讓 Flex 項目在塊維度上佈局的話,爲 flex-direction 設置 columncolumn-reverse。在英語環境下,咱們看見 Flex 項目從 Flex 容器頂部開始、依次往下佈局排列的。

在垂直書寫模式下,塊維度是橫跨頁面的,相似於此種模式下塊元素的排列方式。若是設置了 vertical-lr,則塊元素是從左到右排列的。

See the Pen Smashing Smashing Flexbox Series 1: column in vertical-lr writing mode by Rachel Andrew

但不論塊元素是在什麼方向顯示排列的,若是 flex-direction 設置 column 的話,那麼就是在塊維度上佈局的。

理解了行和列在不一樣的書寫模式中,表如今不一樣的物理方向上,對理解 Grid 和 Flexbox 中的一些術語很是有用。咱們沒有在 Grid 和 Flexbox 中提到「從左到右」或是「從上到下」是由於咱們沒有作任何文檔書寫模式的假設。咱們如今的 CSS 正在變得更加兼容書寫模式,若是你想了解更多表現行爲於此相似的其餘屬性和值的話,能夠閱讀我寫的文章Logical Properties and Values

好了,咱們來總結一下:

  • flex-direction: row
    • 主軸 = 內聯維度
    • main-start 位於在給定書寫模式下句子起始的地方
    • 交叉軸 = 塊維度
  • flex-direction: column
    • 主軸 = 塊維度
    • main-start 位於給定書寫模式下塊元起始佈局的地方
    • 交叉軸 = 內聯維度

默認對齊

使用 display: flex 後,還會有其餘一些事情發生。在這個系列的以後的文章裏,我會好好講解一下對齊。本文中,咱們先來看下使用 display: flex 後,使用的一些默認值。

注意: 對齊屬性最開始起源於 Flexbox 規範。但正如 Flexbox 規範中解釋的那樣,Box Alignment 規範最終將取代 Flexbox 規範中定義的這些屬性。

主軸對齊

justify-content 的初始值是 flex-start,就像咱們在 CSS 中這樣聲明瞭:

.container {
    display: flex;
    justify-content: flex-start;
}
複製代碼

這就是爲何 Flex 項目是從容器的起始邊緣開始排列的緣由。而 row-reverse 則是調換了起始邊緣與結束邊緣,結束邊緣變爲主軸開始的地方。

當你看見以 justify- 前綴開頭的屬性時,說明它是控制 Flexbox 主軸上對齊的。justify-content 操做主軸對齊,全部 Flex 項目在開始處對齊。

除了 flex-starjustify-content 還可以使用的值包括:

  • flex-end
  • center
  • space-around
  • space-between
  • space-evently(在 Box Alignment 中添加)

這些值用於分配 Flex 容器可用空間(available space)。這是項目移動和間隔的緣由。若是使用了 justify-content: space-between,可用空間在項目之間平均分配,固然了,前提是有空間可供分配。若是 Flex 容器空間過窄(全部項目 佈局完成後沒有額外的空間了),justify-content 就不起任何做用了。

咱們能夠設置 flex-directioncolumn 看下,此時 Flex 容器由於沒有設置 height ,因此不存在剩餘空間,justify-content: space-between 也不會起做用。若是你設置一個足夠高的 height,待全部項目 佈局好後,由於還有剩餘空間,就會看到效果。

See the Pen Smashing Flexbox Series 1: column with a height by Rachel Andrew

交叉軸對齊

Flex 項目還能夠在只有一行的 Flex 容器上,執行交叉軸對齊。這種對齊控制的是盒子們在這跟線上的對齊方式。下例中,有一個盒子的內容比其餘的要多,而後其餘盒子像被通知了同樣伸展(stretch)到一樣的高度。這是 align-items 屬性初始值 stretch 在起做用:

See the Pen Smashing Guide to Layout: clearfix by Rachel Andrew

當你看見以 align- 前綴開頭的屬性時,說明它是控制 Flexbox 交叉軸上對齊的。align-items 操做交叉軸對齊,全部 Flex 項目在彈性線(flex line)內對齊。

除了 stretchalign-items 還能夠取的值包括:

  • flex-start
  • flex-end
  • center
  • baseline

若是不想要盒子伸展到最高那個的高度,能夠設置 align-items: flex-start。讓項目在交叉軸的起始邊緣對齊。

See the Pen Smashing Flexbox Series 1: align-items: flex-start by Rachel Andrew

Flex 項目的初始值

Flex 項目是有初始設置的,以下:

  • flex-grow: 0
  • flex-shrink: 1
  • flex-basis: auto

就是說項目默認不會擴展(grow)來填充主軸上的可用空間。若是給 flex-grow 設置了一個正值,那麼項目就會擴展剩餘的空間。

項目的 flex-shrink 屬性處置值爲正值 1,表示能收縮(shrink)。也就是說,當 Flex 容器比較窄的時候,在沒有任何溢出發生的狀況下,項目會變得儘量小。這是一個明智的行爲,通常來講,咱們但願盒子裏的內容不要溢出。

爲了默認可以獲得很好地佈局,flex-basis 初始值使用了 auto。我會在之後的系列文章中解釋這個屬性的行爲。你能夠暫時把它認爲是「大小剛恰好」(big enough to fit the content)。從頁面表現上看的話,就是內容較多的那個項目分配到的空間會比內容少的要多。

See the Pen Smashing Flexbox Series 1: initial values of flex items by Rachel Andrew

這就是使用 Flexbox 帶來的靈活性、設置了 flex-basisauto,在沒有給項目設置額外大小限制的狀況下愛,Flex 項目 有一個基礎尺寸(base size)max-content。這個寬度是指項目中的內容在徹底沒有折行的狀況下的長度。而後每一個項目會 在佔據的基礎尺寸的基礎上,按比例拿走一部分空間,這在 flexbox 規範中有詳情描述。

「注意: Flex shrink 因子分配負空間的時候,是在 Flex 項目的基礎尺寸的基礎之上增長的。最終分配的負空間多少,是根據因子值,按比例分配到每一個項目頭上的。在大一點的項目 沒有顯著收縮以前,小的項目是不會收縮到零的。」

大一點的項目被抽取的空間相對(自身)來講是少的。你能夠比較下面兩張圖,第一張圖裏每一個項目 的內容量差很少,因此看起來差很少是同樣寬的。在第二張圖裏,第三項目的內容比較多,結果看到它分配到了更多的空間。

內容多的項目分配到了更多的空間

Flexbox 在咱們沒有使用更多屬性的前提下,儘量的提供給咱們一個合理的佈局結果。與一刀切平均分配每一個項目 同樣的寬度、致使可能出現有內容多項目被擠壓的很是高的狀況不一樣的是,彈性佈局會給內容多的項目 分配更多的顯示空間。這種行爲是彈性佈局最佳的使用場景。 彈性佈局最擅長於以一種靈活和內容感知的方式——沿着一個軸——放置一組項目。本文到此只是稍微接觸了一些皮毛,在本系列後面的文章中我會適當地講解這些算法。

總結

本文中,咱們講解了彈性佈局中使用到的一些初始值,解釋了當咱們聲明瞭 display: flex 的時候,實際發生了什麼。一路分析下來,發現東西仍是不少的,文中涉及到幾個屬性牽涉到彈性佈局的許多關鍵特性。

彈性佈局如此靈活:默認狀況下,它試圖對內容作出正確選擇——壓縮或拉伸 Flex 項目以得到最佳的可讀性。彈性佈局還支持書寫模式(writing mode):行和列的方向與所使用的書寫模式相關。經過選擇空間的分佈方式,彈性佈局容許將 Flex 項目做爲一個組在主軸上對齊;咱們還能夠在一個伸縮線(flex line)中對齊項目,在交叉軸上以彼此聯繫的方式移動 Flex 項目。重要的是,彈性佈局能感知 Flex 項目的內容大小,會嘗試在沒有設置其餘額外屬性的狀況下,來合理的分配空間給各個 項目。在之後的文章中,咱們將更深刻地討論這些知識點,並作進一步分析什麼時間以及爲何去選擇使用彈性佈局。

(完)

相關文章
相關標籤/搜索