Flexbox

Flexbox 是一種一維佈局方法,用於在行或列中排列專案。專案會伸縮(擴充套件)以填充額外的空間,或收縮以適應較小的空間。本文解釋了所有基礎知識。

先決條件 HTML 基礎知識(學習 HTML 簡介),以及 CSS 工作原理的概念(學習 CSS 簡介)。
目標 學習如何使用 flexbox 佈局系統建立網頁佈局。

為什麼選擇 flexbox?

CSS 彈性盒子佈局使您可以

  • 垂直居中其父元素內的內容塊。
  • 使容器的所有子元素佔用可用寬度/高度的相等部分,而不管可用寬度/高度是多少。
  • 即使多列布局中的列包含不同數量的內容,也使所有列都採用相同的高度。

Flexbox 功能可能是您一維佈局需求的完美解決方案。讓我們深入瞭解一下!

介紹一個簡單的示例

在本文中,您將完成一系列練習,以幫助您瞭解 flexbox 的工作原理。首先,您應該在本地複製第一個入門檔案 — flexbox0.html(來自我們的 GitHub 倉庫)。在現代瀏覽器(如 Firefox 或 Chrome)中載入它,並在程式碼編輯器中檢視程式碼。您也可以 在這裡檢視線上版本

Image showing the starting point of flexbox tutorial

您會看到我們有一個 <header> 元素,其中包含一個頂級標題,以及一個 <section> 元素,其中包含三個 <article>。我們將使用這些元素建立一個相當標準的三列布局。

指定哪些元素作為彈性盒子進行佈局

首先,我們需要選擇哪些元素要作為彈性盒子進行佈局。為此,我們需要在要影響的元素的父元素上設定 display 的特殊值。在本例中,我們希望佈局 <article> 元素,因此我們將其設定為 <section>

css
section {
  display: flex;
}

這會導致 <section> 元素成為Flex 容器,其子元素成為Flex 專案。如下所示

A two row container that includes a single column in the first row and a 3-column layout in the second row that shows how a webpage can be divided into different layouts depending on the contents

此單個宣告為我們提供了所需的一切。令人難以置信,對吧?我們有一個多列布局,其中包含大小相等的列,並且所有列都具有相同的高度。這是因為 Flex 專案(Flex 容器的子元素)的預設值被設定為解決諸如此類的常見問題。

讓我們回顧一下這裡發生了什麼。在元素上新增 displayflex 會將其轉換為 Flex 容器。就其與頁面其餘部分的互動方式而言,容器顯示為 塊級內容。當元素轉換為 Flex 容器時,其子元素會轉換為(並作為)Flex 專案進行佈局。

您可以使用 外部 display(例如,display: inline flex)使容器成為內聯元素,這會影響容器本身在頁面中的佈局方式。傳統的 inline-flex 顯示值也會將容器顯示為內聯元素。在本教程中,我們將重點介紹容器內容的行為,但是如果您想檢視內聯佈局與塊佈局的效果,可以檢視 display 屬性頁面上的值比較

接下來的部分將更詳細地解釋什麼是彈性專案,以及當您將元素設定為彈性容器時,元素內部會發生什麼。

Flex 模型

當元素被佈局為彈性專案時,它們會沿著兩個軸進行佈局。

Three flex items in a left-to-right language are laid out side-by-side in a flex container. The main axis — the axis of the flex container in the direction in which the flex items are laid out — is horizontal. The ends of the axis are main-start and main-end and are on the left and right respectively. The cross axis is vertical; perpendicular to the main axis. The cross-start and cross-end are at the top and bottom respectively. The length of the flex item along the main axis, in this case, the width, is called the main size, and the length of the flex item along the cross axis, in this case, the height, is called the cross size.

  • **主軸**是沿著彈性專案佈局方向延伸的軸(例如,頁面上的一行或頁面下的一列)。該軸的起點和終點分別稱為**主起點**和**主終點**。從主起點邊緣到主終點邊緣的長度稱為**主尺寸**。
  • **交叉軸**是垂直於彈性專案佈局方向延伸的軸。該軸的起點和終點分別稱為**交叉起點**和**交叉終點**。從交叉起點邊緣到交叉終點邊緣的長度稱為**交叉尺寸**。
  • 設定了display: flex屬性的父元素(在我們的示例中為<section>)稱為**彈性容器**。
  • 在彈性容器內作為彈性盒子佈局的專案稱為**彈性專案**(在我們的示例中為<article>元素)。

在閱讀後續部分時,請記住這些術語。如果您對任何用到的術語感到困惑,可以隨時參考它。

列還是行?

Flexbox 提供了一個名為flex-direction的屬性,用於指定主軸的延伸方向(彈性盒子子元素的佈局方向)。預設情況下,此屬性設定為row,這會導致它們按照瀏覽器預設語言的工作方向(對於英文瀏覽器,則為從左到右)排列成一行。

嘗試將以下宣告新增到您的<section>規則中

css
flex-direction: column;

您會看到這將專案重新放回列布局,就像我們在新增任何 CSS 之前一樣。在繼續之前,請從您的示例中刪除此宣告。

注意:您還可以使用row-reversecolumn-reverse值以反向方向佈局彈性專案。也嘗試使用這些值!

換行

在您的佈局中具有固定寬度或高度時,會產生一個問題,即最終您的彈性盒子子元素會溢位其容器,從而破壞佈局。檢視我們的flexbox-wrap0.html示例,並嘗試線上檢視(如果您想按照此示例進行操作,請立即複製此檔案的本地副本)

The Sample flexbox example has all the flex items laid out in a single row of the flex container. The eighth flex item overflows the browser window, and the page has visible horizontal and vertical scroll bars as it cannot be accommodated within the width of the window as the previous seven flex items have taken the space available within the viewport.

在這裡,我們看到子元素確實溢位了其容器。預設情況下,如果flex-direction設定為row,瀏覽器會嘗試將所有彈性專案放置在同一行中;如果flex-direction設定為column,則會放置在同一列中。解決此問題的一種方法是將以下宣告新增到您的<section>規則中

css
flex-wrap: wrap;

此外,將以下宣告新增到您的<article>規則中

css
flex: 200px;

現在試試看。您會看到包含此聲明後佈局看起來好多了。

Flex items are laid out in multiple rows in the flex container. The flex-wrap property is set to 'wrap' in the flex container which displays the flex items in a new row if the flex items in the previous row overflow outside the flexbox container. Each flex item is given a width of 200 pixels. All the items are stretched to be the same height, as tall as the flex item with the most content.

現在我們有多行。每行包含儘可能多的彈性盒子子元素。任何溢位都會向下移動到下一行。flex: 200px宣告設定在文章上,這意味著每個文章的寬度至少為200px。我們稍後將更詳細地討論此屬性。您可能還會注意到,最後一行上的最後幾個子元素都變寬了,以便仍然填滿整行。

但是我們還可以在這裡做更多的事情。首先,嘗試將您的flex-direction屬性值更改為row-reverse。現在您會看到,您仍然擁有多行佈局,但它從瀏覽器視窗的相對角開始並反向流動。

flex-flow 簡寫

在這一點上,值得注意的是,flex-directionflex-wrap存在一個簡寫形式:flex-flow。例如,您可以替換

css
flex-direction: row;
flex-wrap: wrap;

css
flex-flow: row wrap;

Flex 專案的靈活大小調整

現在讓我們回到我們的第一個示例,看看如何控制彈性專案相對於其他彈性專案佔據的空間比例。開啟您本地複製的flexbox0.html,或將flexbox1.html作為新的起點複製一份(線上檢視)。

首先,將以下規則新增到 CSS 的底部

css
article {
  flex: 1;
}

這是一個無單位的比例值,它決定了每個彈性專案沿主軸佔據的空間相對於其他彈性專案的多少。在本例中,我們為每個<article>元素提供了相同的值(值為1),這意味著它們都將佔用填充和邊距等屬性設定後剩餘的相同數量的空閒空間。此值在彈性專案之間按比例共享:為每個彈性專案提供值為400000的值將產生完全相同的效果。

現在在前面規則的下方新增以下規則

css
article:nth-of-type(3) {
  flex: 2;
}

現在重新整理頁面,您會看到第三個<article>佔據的可用寬度是其他兩個的兩倍。現在總共有四個比例單位可用(因為 1 + 1 + 2 = 4)。前兩個彈性專案各有 1 個單位,因此它們分別佔用可用空間的 1/4。第三個有 2 個單位,因此它佔據了可用空間的 2/4(或一半)。

您還可以指定 flex 值內的最小尺寸值。嘗試像這樣更新您現有的文章規則

css
article {
  flex: 1 200px;
}

article:nth-of-type(3) {
  flex: 2 200px;
}

這基本上表示:“每個彈性專案首先將獲得可用空間的200px。之後,剩餘的可用空間將根據比例單位共享。”嘗試重新整理,您會看到空間共享方式的不同。

A flex container with three flex items. The third flex item is slightly larger than the first two.

所有彈性專案的最小寬度均為 200 畫素,使用“flex”設定。前兩個彈性專案的 flex 值為 1,第三個專案的 flex 值為 2。這將彈性容器中剩餘的空間分成 4 個比例單位。一個單位分配給前兩個彈性專案中的每一個,2 個單位分配給第三個彈性專案,使第三個彈性專案比其他兩個彈性專案更寬,而其他兩個彈性專案的寬度相同。

Flexbox 的真正價值體現在其靈活性和響應性上。如果您調整瀏覽器視窗大小或新增另一個<article>元素,佈局將繼續正常工作。

flex:簡寫與完整寫法

flex是一個簡寫屬性,最多可以指定三個不同的值

  • 我們上面討論過的無單位比例值。這可以使用flex-grow完整屬性單獨指定。
  • 第二個無單位比例值flex-shrink,當彈性專案溢位其容器時,它就會發揮作用。此值指定為了防止溢位,專案將縮小多少。這是一個相當高階的 Flexbox 功能,我們不會在本文章中進一步介紹它。
  • 我們上面討論過的最小尺寸值。這可以使用flex-basis完整值單獨指定。

我們建議您不要使用完整形式的 flex 屬性,除非您確實需要這樣做(例如,覆蓋之前設定的內容)。它們會導致編寫大量額外的程式碼,並且可能有點令人困惑。

水平和垂直對齊

您還可以使用 Flexbox 功能沿主軸或交叉軸對齊彈性專案。讓我們透過檢視一個新示例來探索這一點:flex-align0.html線上檢視)。我們將把它變成一個簡潔、靈活的按鈕/工具欄。目前,您會看到一個水平選單欄,其中一些按鈕擠在左上角。

Five buttons are laid out in a row in a flex container. The buttons are jammed into the top left-hand corner that doesn't look neat.

首先,複製此示例的本地副本。

現在,將以下內容新增到示例 CSS 的底部

css
div {
  display: flex;
  align-items: center;
  justify-content: space-around;
}

Five buttons are laid out in a row in a flex container. The flex items are positioned vertically centered and they are evenly spaced out horizontally.

重新整理頁面,您會看到按鈕現在水平和垂直居中。我們透過兩個新屬性完成了此操作。透過將align-items屬性設定為center,彈性專案位於交叉軸的中心。透過將justify-content屬性設定為space-around,彈性專案沿主軸均勻分佈。

align-items屬性控制彈性專案在交叉軸上的位置。

  • 預設情況下,值為normal,在 Flexbox 中的行為與stretch相同。這會將所有彈性專案拉伸以填充父元素在交叉軸方向上的區域。如果父元素在交叉軸方向上沒有固定大小,則所有彈性專案的高度(或寬度)都將與最高的(或最寬的)彈性專案相同。這就是我們的第一個示例預設情況下具有等高列的原因。
  • 我們在上面程式碼中使用的center值會導致專案保持其固有尺寸,但在交叉軸上居中。這就是我們當前示例的按鈕垂直居中的原因。
  • 您還可以使用諸如flex-startself-startstart以及flex-endself-endend之類的值,它們將分別在交叉軸的開頭和結尾處對齊所有專案。baseline值將根據其基線對齊彈性專案;基本上,每個彈性專案第一行文字的底部將與具有最大距離(從交叉起點到該基線)的元素的第一行底部對齊。有關完整詳細資訊,請參閱align-items

您可以透過將align-self屬性應用於單個彈性專案來覆蓋align-items的行為。例如,嘗試將以下內容新增到您的 CSS 中

css
button:first-child {
  align-self: flex-end;
}

Five buttons are laid out in a row in a flex container. All the flex items except the first one are positioned at the center of the cross-axis, or vertically centered. The first item is flush against the bottom of the flex container, at the end of the cross-axis The flex items are spaced evenly along the main-axis, or width, of the container.

看看這會產生什麼影響,並在完成後將其刪除。

justify-content控制彈性專案在主軸上的位置。

  • 預設值為normal,其行為與start相同,這使得所有專案都位於主軸的開頭。
  • 您可以使用endflex-end使其位於末尾。
  • leftright值的行為與startend相同,具體取決於書寫模式方向。
  • center也是justify-content的值。它將使彈性專案位於主軸的中心。
  • 我們在上面使用的值space-around非常有用——它將所有專案均勻地分佈在主軸上,並在兩端留出一些空間。
  • 還有另一個值space-between,它與space-around非常相似,只是它在兩端不留任何空間。

justify-items屬性在 Flexbox 佈局中被忽略。

我們鼓勵您在繼續之前嘗試這些值以瞭解它們是如何工作的。

Flex 專案排序

Flexbox 還具有一個功能,可以更改彈性專案的佈局順序,而不會影響源順序。這是傳統佈局方法無法實現的另一件事。

嘗試將以下 CSS 新增到您的按鈕欄示例程式碼中

css
button:first-child {
  order: 1;
}

重新整理頁面,您會看到“Smile”按鈕已移動到主軸的末尾。讓我們更詳細地討論一下它是如何工作的

  • 預設情況下,所有彈性專案的order值都為0
  • 具有較高指定順序值的彈性專案將在顯示順序中出現在具有較低順序值的專案之後。
  • 具有相同順序值的彈性專案將按其源順序出現。因此,如果您有四個專案的順序值分別設定為2110,則它們的顯示順序將是第 4 個、第 2 個、第 3 個,然後是第 1 個。
  • 第 3 個專案出現在第 2 個專案之後,因為它具有相同的順序值,並且在源順序中位於其之後。

您可以設定負順序值,使專案出現在值為0的專案之前。例如,您可以使用以下規則使“Blush”按鈕出現在主軸的開頭

css
button:last-child {
  order: -1;
}

雖然您可以使用order更改順序,但選項卡順序與程式碼順序相同。更改可聚焦元素的順序會對鍵盤使用者的可用性產生負面影響!

巢狀 Flex 盒子

可以使用 Flexbox 建立一些非常複雜的佈局。將彈性專案也設定為彈性容器完全沒問題,以便其子元素也像彈性盒子一樣佈局。檢視complex-flexbox.html線上檢視)。

The Sample flexbox example has three flex item children laid out in a row. The first two are the same width, the third is slightly wider. The third flex item is also a flex container. It has a set of buttons in two rows followed by text. The first row of buttons has 4 buttons that are laid out in a row; the buttons are the same width, taking up the full width of the container. The second row has a single button that takes up the entire width of the row on its own.

此複雜佈局有一些彈性專案,它們也是彈性容器。此 HTML 非常簡單。我們有一個包含三個<article><section>元素。第三個<article>包含三個<div>,第一個<div>包含五個<button>

section - article
          article
          article - div - button
                    div   button
                    div   button
                          button
                          button

讓我們看看我們用於佈局的程式碼。

首先,我們將<section>的子元素設定為彈性盒子佈局。

css
section {
  display: flex;
}

接下來,我們在<article>本身設定一些 flex 值。請特別注意這裡的第二個規則:我們將第三個<article>設定為其子元素也像彈性專案一樣佈局,但這次我們將它們像列一樣佈局。

css
article {
  flex: 1 200px;
}

article:nth-of-type(3) {
  flex: 3 200px;
  display: flex;
  flex-flow: column;
}

接下來,我們選擇第一個<div>。我們首先使用flex: 1 100px;有效地為其提供100px的最小高度,然後將其子元素(<button>元素)也設定為彈性盒子佈局。在這裡,我們將它們佈局成一個換行的行,並像我們在前面看到的單個按鈕示例中一樣,將它們對齊到可用空間的中心。

css
article:nth-of-type(3) div:first-child {
  flex: 1 100px;
  display: flex;
  flex-flow: row wrap;
  align-items: center;
  justify-content: space-around;
}

最後,我們設定按鈕的一些大小。這次透過為其提供1 auto的 flex 值。這會產生非常有趣的效果,如果您嘗試調整瀏覽器視窗寬度,您會看到。按鈕將佔用盡可能多的空間。一行將適合儘可能多的按鈕;超出此範圍,它們將換行。

css
button {
  flex: 1 auto;
  margin: 5px;
  font-size: 18px;
  line-height: 1.5;
}

測試您的技能!

您已閱讀完本文,但您還記得最重要的資訊嗎?在繼續之前,您可以找到一些進一步的測試來驗證您是否保留了這些資訊——請參閱測試您的技能:Flexbox

總結

這結束了我們對 Flexbox 基礎知識的介紹。我們希望您玩得開心,並在學習過程中多加練習。接下來,我們將看看 CSS 佈局的另一個重要方面:CSS 網格

另請參閱