Flex佈局

caoruipeng發表於2024-06-23

flex 佈局的基本概念

Flexible Box 模型,通常被稱為 flexbox,是一種一維的佈局模型。它給 flexbox 的子元素之間提供了強大的空間分佈和對齊能力。本文給出了 flexbox 的主要特性,更多的細節將在別的檔案中探索。

我們說 flexbox 是一種一維的佈局,是因為一個 flexbox 一次只能處理一個維度上的元素佈局,一行或者一列。作為對比的是另外一個二維佈局 CSS Grid Layout,可以同時處理行和列上的佈局。

flexbox 的兩根軸線

當使用 flex 佈局時,首先想到的是兩根軸線 — 主軸和交叉軸。主軸由 flex-direction 定義,另一根軸垂直於它。我們使用 flexbox 的所有屬性都跟這兩根軸線有關,所以有必要在一開始首先理解它。

主軸

主軸由 flex-direction 定義,可以取 4 個值:

  • row
  • row-reverse
  • column
  • column-reverse

如果你選擇了 row 或者 row-reverse,你的主軸將沿著 inline 方向延伸。

If flex-direction is set to row the main axis runs along the row in the inline direction.

選擇 column 或者 column-reverse 時,你的主軸會沿著上下方向延伸 — 也就是 block 排列的方向。

If flex-direction is set to column the main axis runs in the block direction.

交叉軸

交叉軸垂直於主軸,所以如果你的flex-direction (主軸) 設成了 row 或者 row-reverse 的話,交叉軸的方向就是沿著列向下的。

If flex-direction is set to row then the cross axis runs in the block direction.

如果主軸方向設成了 column 或者 column-reverse,交叉軸就是水平方向。

If flex-direction is set to column then the cross axis runs in the inline direction.

理解主軸和交叉軸的概念對於對齊 flexbox 裡面的元素是很重要的;flexbox 的特性是沿著主軸或者交叉軸對齊之中的元素。

起始線和終止線

另外一個需要理解的重點是 flexbox 不會對檔案的書寫模式提供假設。過去,CSS 的書寫模式主要被認為是水平的,從左到右的。現代的佈局方式涵蓋了書寫模式的範圍,所以我們不再假設一行文字是從檔案的左上角開始向右書寫,新的行也不是必須出現在另一行的下面。

你可以在接下來的文章中學到更多 flexbox 和書寫模式關係的詳細說明。下面的描述是來幫助我們理解為什麼不用上下左右來描述 flexbox 元素的方向。

如果 flex-direction 是 row ,並且我是在書寫英文,那麼主軸的起始線是左邊,終止線是右邊。

Working in English the start edge is on the left.

如果我在書寫阿拉伯文,那麼主軸的起始線是右邊,終止線是左邊。

The start edge in a RTL language is on the right.

在這兩種情況下,交叉軸的起始線是 flex 容器的頂部,終止線是底部,因為兩種語言都是水平書寫模式。

之後,你會覺得用起始和終止來描述比左右更合適,這會對你理解其他相同模式的佈局方法(例如:CSS Grid Layout)起到幫助的作用。

Flex 檔案中採用了 flexbox 的區域就叫做 flex 容器。為了建立 flex 容器,我們把一個容器的 display 屬性值改為 flex 或者 inline-flex。完成這一步之後,容器中的直系子元素就會變為 flex 元素。所有 CSS 屬性都會有一個初始值,所以 flex 容器中的所有 flex 元素都會有下列行為:

  • 元素排列為一行 (flex-direction 屬性的初始值是 row)。
  • 元素從主軸的起始線開始。
  • 元素不會在主維度方向拉伸,但是可以縮小。
  • 元素被拉伸來填充交叉軸大小。
  • flex-basis 屬性為 auto
  • flex-wrap 屬性為 nowrap

這會讓你的元素呈線形排列,並且把自己的大小作為主軸上的大小。如果有太多元素超出容器,它們會溢位而不會換行。如果一些元素比其他元素高,那麼元素會沿交叉軸被拉伸來填滿它的大小。

更改 flex 方向 flex-direction

在 flex 容器中新增 flex-direction 屬性可以讓我們更改 flex 元素的排列方向。設定 flex-direction: row-reverse 可以讓元素沿著行的方向顯示,但是起始線和終止線位置會交換。

把 flex 容器的屬性 flex-direction 改為 column ,主軸和交叉軸交換,元素沿著列的方向排列顯示。改為 column-reverse ,起始線和終止線交換。

下面的例子中,flex-direction 值為 row-reverse。嘗試使用其他的值 row ,columncolumn-reverse,看看內容會發生什麼改變。

用 flex-wrap 實現多行 Flex 容器

雖然flexbox是一維模型,但可以使我們的flex專案應用到多行中。在這樣做的時候,您應該把每一行看作一個新的flex容器。任何空間分佈都將在該行上發生,而不影響該空間分佈的其他行。

為了實現多行效果,請為屬性flex-wrap新增一個屬性值wrap。現在,如果您的專案太大而無法全部顯示在一行中,則會換行顯示。下面的實時例子包含已給出寬度的專案,對於flex容器,專案的子元素總寬度大於容器最大寬度。由於flex-wrap的值設定為wrap,所以專案的子元素換行顯示。若將其設定為nowrap,這也是初始值,它們將會縮小以適應容器,因為它們使用的是允許縮小的初始Flexbox值。如果專案的子元素無法縮小,使用nowrap會導致溢位,或者縮小程度還不夠

在指南中您可以瞭解更多關於 flex-wrap的資訊 Mastering Wrapping of Flex Items.

簡寫屬性 flex-flow

你可以將兩個屬性 flex-direction 和 flex-wrap 組合為簡寫屬性 flex-flow。第一個指定的值為 flex-direction ,第二個指定的值為 flex-wrap.

在下面的例子中,嘗試將第一個值修改為 flex-direction 的允許取值之一,即 rowrow-reversecolumn 或 column-reverse, 並嘗試將第二個指定值修改為 wrap 或 nowrap

flex 元素上的屬性

為了更好地控制 flex 元素,有三個屬性可以作用於它們:

在這裡,我們只會大概介紹一下它們的用法,更詳細的細節請參閱其它的文章。

在考慮這幾個屬性的作用之前,需要先了解一下 可用空間 available space 這個概念。這幾個 flex 屬性的作用其實就是改變了 flex 容器中的可用空間的行為。同時,可用空間對於 flex 元素的對齊行為也是很重要的。

假設在 1 個 500px 的容器中,我們有 3 個 100px 寬的元素,那麼這 3 個元素需要佔 300px 的寬,剩下 200px 的可用空間。在預設情況下,flexbox 的行為會把這 200px 的空間留在最後一個元素的後面。

This flex container has available space after laying out the items.

如果期望這些元素能自動地擴充套件去填充滿剩下的空間,那麼我們需要去控制可用空間在這幾個元素間如何分配,這就是元素上的那些 flex 屬性要做的事。

Flex 元素屬性:flex-basis

flex-basis 定義了該元素的空間大小(the size of that item in terms of the space),flex 容器裡除了元素所佔的空間以外的富餘空間就是可用空間 available space。該屬性的預設值是 auto 。此時,瀏覽器會檢測這個元素是否具有確定的尺寸。在上面的例子中,所有元素都設定了寬度(width)為 100px,所以 flex-basis 的值為 100px。

如果沒有給元素設定尺寸,flex-basis 的值採用元素內容的尺寸。這就解釋了:我們給只要給 Flex 元素的父元素宣告 display: flex ,所有子元素就會排成一行,且自動分配小大以充分展示元素的內容。

Flex 元素屬性:flex-grow

flex-grow 若被賦值為一個正整數,flex 元素會以 flex-basis 為基礎,沿主軸方向增長尺寸。這會使該元素延展,並佔據此方向軸上的可用空間(available space)。如果有其他元素也被允許延展,那麼他們會各自佔據可用空間的一部分。

如果我們給上例中的所有元素設定 flex-grow 值為 1,容器中的可用空間會被這些元素平分。它們會延展以填滿容器主軸方向上的空間。

flex-grow 屬性可以按比例分配空間。如果第一個元素 flex-grow 值為 2,其他元素值為 1,則第一個元素將佔有 2/4(上例中,即為 200px 中的 100px), 另外兩個元素各佔有 1/4(各 50px)。

Flex 元素屬性: flex-shrink

flex-grow屬性是處理 flex 元素在主軸上增加空間的問題,相反flex-shrink屬性是處理 flex 元素收縮的問題。如果我們的容器中沒有足夠排列 flex 元素的空間,那麼可以把 flex 元素flex-shrink屬性設定為正整數來縮小它所佔空間到flex-basis以下。與flex-grow屬性一樣,可以賦予不同的值來控制 flex 元素收縮的程度 —— 給flex-shrink屬性賦予更大的數值可以比賦予小數值的同級元素收縮程度更大。

在計算 flex 元素收縮的大小時,它的最小尺寸也會被考慮進去,就是說實際上 flex-shrink 屬性可能會和 flex-grow 屬性表現的不一致。因此,我們可以在文章《控制 Flex 子元素在主軸上的比例》中更詳細地看一下這個演演算法的原理。

備註: 在給 flex-grow 和 flex-shrink 賦值時要注意比例。如果我們給所有 flex 元素的 flex 屬性賦值為 1 1 200px ,並且希望其中一個元素可以增加到 2 倍,我們可以給該元素的 flex 屬性賦值為2 1 200px。當然,你也可以選擇賦值為 flex: 10 1 200px 和 flex: 20 1 200px 。

Flex 屬性的簡寫

你可能很少看到 flex-growflex-shrink,和 flex-basis 屬性單獨使用,而是混合著寫在 flex 簡寫形式中。 Flex 簡寫形式允許你把三個數值按這個順序書寫 — flex-growflex-shrinkflex-basis

你可以在下面的例項中嘗試把 flex 簡寫形式中的數值更改為不同數值,但要記得第一個數值是 flex-grow。賦值為正數的話是讓元素增加所佔空間。第二個數值是flex-shrink — 正數可以讓它縮小所佔空間,但是隻有在 flex 元素總和超出主軸才會生效。最後一個數值是 flex-basis;flex 元素是在這個基準值的基礎上縮放的。

 

大多數情況下可以用預定義的簡寫形式。在這個教程中你可能經常會看到這種寫法,許多情況下你都可以這麼使用。下面是幾種預定義的值:

  • flex: initial
  • flex: auto
  • flex: none
  • flex: <positive-number>

flex: initial 是把 flex 元素重置為 Flexbox 的初始值,它相當於 flex: 0 1 auto。在這裡 flex-grow 的值為 0,所以 flex 元素不會超過它們 flex-basis 的尺寸。flex-shrink 的值為 1, 所以可以縮小 flex 元素來防止它們溢位。flex-basis 的值為 auto. Flex 元素尺寸可以是在主維度上設定的,也可以是根據內容自動得到的。

flex: auto 等同於 flex: 1 1 auto;和上面的 flex:initial 基本相同,但是這種情況下,flex 元素在需要的時候既可以拉伸也可以收縮。

flex: none 可以把 flex 元素設定為不可伸縮。它和設定為 flex: 0 0 auto 是一樣的。元素既不能拉伸或者收縮,但是元素會按具有 flex-basis: auto 屬性的 flexbox 進行佈局。

你在教程中常看到的 flex: 1 或者 flex: 2 等等。它相當於flex: 1 1 0 或者 flex: 2 1 0。元素可以在 flex-basis 為 0 的基礎上伸縮。

嘗試在下面的例項中應用這些簡寫值。

 

元素間的對齊和空間分配

Flexbox 的一個關鍵特性是能夠設定 flex 元素沿主軸方向和交叉軸方向的對齊方式,以及它們之間的空間分配。

align-items

align-items 屬性可以使元素在交叉軸方向對齊。

這個屬性的初始值為stretch,這就是為什麼 flex 元素會預設被拉伸到最高元素的高度。實際上,它們被拉伸來填滿 flex 容器 —— 最高的元素定義了容器的高度。

你也可以設定align-items的值為flex-start,使 flex 元素按 flex 容器的頂部對齊,flex-end 使它們按 flex 容器的下部對齊,或者center使它們居中對齊。在例項中嘗試——我給出了 flex 容器的高度,以便你可以看到元素在容器中移動。看看如果更改 align-items 的值為下列值會發生什麼:

  • stretch
  • flex-start
  • flex-end
  • center

 

justify-content

justify-content屬性用來使元素在主軸方向上對齊,主軸方向是透過 flex-direction 設定的方向。初始值是flex-start,元素從容器的起始線排列。但是你也可以把值設定為flex-end,從終止線開始排列,或者center,在中間排列。

你也可以把值設定為space-between,把元素排列好之後的剩餘空間拿出來,平均分配到元素之間,所以元素之間間隔相等。或者使用space-around,使每個元素的左右空間相等。

在例項中嘗試下列justify-content屬性的值:

  • stretch
  • flex-start
  • flex-end
  • center
  • space-around
  • space-between

 

在以後的文章中,為了更好的理解它們怎麼使用,我們會更深入的探索這些屬性。然而,這些簡單的例子對大多數應用都很有幫助。