Flexbox

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

預備知識 使用 HTML 構造內容CSS 樣式基礎文字和字型樣式基礎,熟悉CSS 佈局基本概念
學習成果
  • flexbox 的目的——以一維方式靈活地佈局一組塊級或內聯元素。
  • Flex 術語——flex 容器、flex 專案、主軸和交叉軸。
  • 理解 display: flex 預設提供的內容。
  • 如何將內容換行到新行和新列。
  • flex 專案的彈性尺寸和排序。
  • 內容對齊和分散對齊。

為什麼選擇 flexbox?

CSS 彈性盒佈局使你能夠

  • 在父級中垂直居中一個塊級內容。
  • 使容器的所有子元素佔據可用寬度/高度的相等部分,無論可用寬度/高度是多少。
  • 即使多列布局中的所有列包含不同數量的內容,也能使它們採用相同的高度。

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

注意: Scrimba 的Flexbox MDN 學習夥伴 入門 scrim 提供了一個互動式指南,涵蓋了 flexbox 在 Web 上的常見程度以及為什麼學習它如此重要,並引導您完成一個典型的用例,演示了 flexbox 的強大功能。

介紹一個簡單示例

在本文中,您將透過一系列練習來幫助您理解 flexbox 的工作原理。要開始,您應該建立 HTML 和 CSS 的本地副本。在現代瀏覽器(如 Firefox 或 Chrome)中載入它,並在您的程式碼編輯器中檢視程式碼。或者,點選“播放”按鈕在 playground 中開啟它。

html
<header>
  <h1>Sample flexbox example</h1>
</header>
<section>
  <article>
    <h2>First article</h2>
    <p>Content…</p>
  </article>
  <article>
    <h2>Second article</h2>
    <p>Content…</p>
  </article>
  <article>
    <h2>Third article</h2>
    <p>Content…</p>
  </article>
</section>
css
body {
  font-family: sans-serif;
  margin: 0;
}
header {
  background: purple;
  height: 100px;
}
h1 {
  text-align: center;
  color: white;
  line-height: 100px;
  margin: 0;
}
section {
  zoom: 0.8;
}
article {
  padding: 10px;
  margin: 10px;
  background: aqua;
}
/* Add your flexbox CSS below here */

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

指定哪些元素以彈性盒佈局

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

css
section {
  display: flex;
}

這將導致 <section> 元素成為flex 容器,其子元素成為flex 專案。這就是它的樣子:

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

讓我們回顧一下這裡發生了什麼。向元素新增 flexdisplay 值會使其成為 flex 容器。該容器在與頁面其餘部分的互動方式上顯示為塊級內容。當元素轉換為 flex 容器時,其子元素將轉換為(並佈局為)flex 專案。

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

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

彈性模型

當元素作為 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.

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

在後續章節中請牢記這些術語。如果您對使用的任何術語感到困惑,可以隨時回顧。

列或行?

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

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

css
flex-direction: column;

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

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

換行

當您的佈局具有固定寬度或高度時,會出現一個問題:您的 flexbox 子元素最終會溢位其容器,從而破壞佈局。在以下示例中,我們有 5 個 <article>,它們不適合,因為它們具有 400pxmin-width,因此會出現水平滾動。

在這裡我們看到子元素確實溢位了它們的容器。預設情況下,如果 flex-direction 設定為 row,瀏覽器會嘗試將所有 flex 專案放置在單行中;如果 flex-direction 設定為 column,則放置在單列中。

解決此問題的一種方法是將以下宣告新增到您的 <section> 規則中:

css
section {
  flex-wrap: wrap;
}

您會看到,包含此內容後,佈局看起來好多了:

我們現在有多行。每行都儘可能合理地容納了許多 flexbox 子元素。任何溢位都向下移動到下一行。

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

flex-flow 縮寫

此時值得注意的是,flex-directionflex-wrap 有一個縮寫:flex-flow。例如,您可以替換:

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

with

css
flex-flow: row wrap;

flex 專案的彈性尺寸

現在讓我們回到第一個示例,看看如何控制 flex 專案所佔空間與其他 flex 專案相比的比例。

在本地副本中,將以下規則新增到 CSS 的底部:

css
article {
  flex: 1;
}

這是一個無單位的比例值,它決定了每個 flex 專案沿主軸佔據可用空間的多少,與其他 flex 專案相比。在這種情況下,我們為每個 <article> 元素賦予相同的值(值 1),這意味著它們都將佔據在設定了 padding 和 margin 等屬性後剩餘的空閒空間的相等部分。這個值在 flex 專案之間按比例共享:給每個 flex 專案一個值 400000 會產生完全相同的效果。

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

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

現在當你重新整理時,你會看到第三個 <article> 佔據的可用寬度是其他兩個的兩倍。現在總共有四個比例單位(因為 1 + 1 + 2 = 4)。前兩個 flex 專案各有一個單位,所以它們各佔據可用空間的 1/4。第三個有兩個單位,所以它佔據可用空間的 2/4(或一半)。

你也可以在 flex 值中指定一個最小尺寸值。嘗試像這樣更新你現有的文章規則:

css
article {
  flex: 1 100px;
}

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

這基本上說明,“每個彈性專案將首先獲得 100px 的可用空間。之後,剩餘的可用空間將根據比例單位進行共享。”您將看到空間共享方式的不同。

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

flexbox 的真正價值體現在其靈活性/響應性。如果您調整瀏覽器視窗大小或新增另一個 <article> 元素,佈局仍然可以正常工作。

flex:縮寫與長寫

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

  • 我們上面討論的無單位比例值。這可以使用 flex-grow 長寫屬性單獨指定。
  • 第二個無單位比例值,flex-shrink,當 flex 專案溢位其容器時生效。此值指定專案將收縮多少以防止溢位。這是一個相當高階的 flexbox 功能,我們不會在本文中進一步討論。
  • 我們上面討論的最小尺寸值。這可以使用 flex-basis 長寫值單獨指定。

我們建議您除非真正必要(例如,覆蓋之前設定的內容),否則不要使用長寫 flex 屬性。它們會導致編寫大量額外程式碼,並且可能會有些混亂。

水平和垂直對齊

您還可以使用 flexbox 功能沿主軸或交叉軸對齊 flex 專案。讓我們透過檢視一個新示例來探索這一點。

html
<div>
  <button>Smile</button>
  <button>Laugh</button>
  <button>Wink</button>
  <button>Shrug</button>
  <button>Blush</button>
</div>
css
body {
  font-family: sans-serif;
  width: 90%;
  max-width: 960px;
  margin: 10px auto;
}
div {
  height: 100px;
  border: 1px solid black;
}
button {
  font-size: 18px;
  line-height: 1.5;
  width: 15%;
}
/* Add your flexbox CSS below here */

我們將把它變成一個整潔靈活的按鈕/工具欄。目前,您會看到一個水平選單欄,其中一些按鈕擠在左上角。

首先,獲取此示例的本地副本。

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

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

重新整理頁面,您會看到按鈕現在在水平和垂直方向上都很好地居中。我們透過兩個新屬性實現了這一點。透過將 align-items 屬性設定為 center,flex 專案位於交叉軸的中心。透過將 justify-content 屬性設定為 space-around,flex 專案沿主軸均勻分佈。

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

  • 預設情況下,值為 normal,在 flexbox 中其行為類似於 stretch。這將所有 flex 專案拉伸以填充父元素在交叉軸方向上的空間。如果父元素在交叉軸方向上沒有固定大小,那麼所有 flex 專案將變得與最高(或最寬)的 flex 專案一樣高(或寬)。這就是為什麼我們第一個示例的列預設高度相等的原因。
  • 我們在上面的程式碼中使用的 center 值導致專案保持其固有尺寸,但在交叉軸上居中。這就是我們當前示例中的按鈕垂直居中的原因。
  • 你也可以使用 flex-startself-startstartflex-endself-endend 等值,它們將分別將所有專案對齊到交叉軸的起始和結束位置。baseline 值將使 flex 專案按其基線對齊;基本上,每個 flex 專案第一行文字的底部將與交叉起始點與該基線之間距離最大的元素第一行底部對齊。有關詳細資訊,請參閱 align-items

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

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

看看這有什麼影響,完成後再將其刪除。

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

  • 預設值為 normal,其行為等同於 start,這使得所有專案都位於主軸的起始位置。
  • 你可以使用 endflex-end 使它們位於末尾。
  • leftright 值根據書寫模式方向的行為與 startend 相同。
  • center 也是 justify-content 的一個值。它將使 flex 專案位於主軸的中心。
  • 我們上面使用的值 space-around 很有用——它將所有專案沿主軸均勻分佈,兩端留有一些空間。
  • 還有一個值,space-between,它與 space-around 非常相似,只是它兩端不留任何空間。

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

我們鼓勵您在繼續之前嘗試使用這些值,看看它們是如何工作的。

排序彈性項

Flexbox 還有一個功能,可以改變 flex 專案的佈局順序而不影響源順序。這是傳統佈局方法無法實現的另一個功能。

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

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

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

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

您可以設定負數 order 值,使專案出現在值為 0 的專案之前。例如,您可以使用以下規則使“Blush”按鈕出現在主軸的起始位置:

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

雖然可以使用 order 改變順序,但 Tab 鍵的焦點順序保持與程式碼順序相同。改變可聚焦元素的順序可能會對使用鍵盤的使用者造成負面影響!

巢狀彈性盒

使用 flexbox 可以建立一些相當複雜的佈局。將 flex 專案也設定為 flex 容器是完全可以的,這樣其子元素也像彈性盒一樣佈局。

這個複雜的佈局中有幾個 flex 專案也是 flex 容器。它的 HTML 相當簡單。我們有一個 <section> 元素,其中包含三個 <article>。第三個 <article> 包含三個 <div>,第一個 <div> 包含五個 <button>

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

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

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

css
section {
  display: flex;
}

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

css
article {
  flex: 1 100px;
}

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

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

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 基礎知識的介紹就結束了。我們希望您玩得開心,並在進一步學習時好好嘗試。在下一篇文章中,我們將為您提供一些測試,您可以使用它們來檢查您對所有這些資訊的理解和掌握程度。

另見