請啟用 Javascript 查看內容

CSS筆記 - Flexbox

 ·  ☕ 10 分鐘

這週是 六角鼠年鐵人賽 第三週,不知道要寫啥,就重新整理了一下 Flexbox 的筆記。

Flexbox 概述

Flexbox 全稱為 CSS Flexible Box Layout,也就是 CSS 彈性盒子佈局。是一種新的 CSS3 佈局模式,在彈性盒子佈局中,彈性容器的子項目們可以伸展到任何方向、並讓他們的尺寸更加「彈性」、或者持續增大,以填補未使用的空間,抑或縮小,以避免父元素溢出。子元素的橫向或縱向對齊都很容易操作。

1. 為何流行?

為何開始流行了呢?最主要也是因為 CSS3 的規範終於普及,加上行動裝置的發展促成了響應式佈局興起,自適應長寬彈性相當大的 Flexbox 就趁勢而起了。

  • 非常適合單向排版,例如導覽列、Gird-Layout
  • 許多 CSS 框架也使用(Bootstrap、Foundation 等)

跟毒品一樣,用過就回不去了。

2. 瀏覽器的支援

瀏覽器支援高達 97%。

Can I use CSS Flexible Box Layout Module ?

3. Flexbox 規格歷史

  • 2009 年的版本:display: box 現在已經不再跟 Flexbox 有任何關係。
  • 2011 過渡期版本:display: flexbox 只是草稿,只被 IE10 實作, 如果可能的話應該避免使用。
  • 2012 最終版:display: flex

模型概念


來源:CSS彈性盒子用法|MDN

容器與項目:

  • 彈性容器(Flex container)
    將元素的 display 屬性設為 flexinline-flex,就會變彈性容器。
  • 彈性項目(Flex item)
    所有彈性容器的子元素都會變成彈性項目,包含文字。

彈性容器具有主軸與交錯軸:

  • 主軸(main axis)
  • 交錯軸(cross axis)

方向:

  • 主軸起點與終點(main start/main end)
  • 交錯軸點與終點(cross start/cross end)

彈性項目具有:

  • 水平尺寸與垂直尺寸(main size、cross size)

屬性介紹

Flexbox 可分成外層元素(彈性容器)與內層元素(彈性項目)。

外容器屬性:

  • displayflexinline-flex,啟用 Flexbox 的必備屬性
  • flex-flow
    • flex-direction:決定主軸線的方向
    • flex-wrap:決定是否換行
  • justify-content:主軸線的對齊
  • align-items:交錯軸的對齊
  • align-content:整體的對齊

內層元素屬性:

  • align-self:單一個物件的交錯軸對齊
  • order:排序
  • flex
    • flex-grow:伸展比,其數值與其它物件可分配伸展比有關
    • flex-shrink:收縮比
    • flex-basis:絕對值

1. Emmet 速寫格式

Flexbox 相關屬性的 Emmet 速寫格式:

display

  • d:fdisplay:flex;
  • d:ifdisplay:inline-flex;

flex-direction

  • fxdflex-direction:;
  • fxd:cflex-direction:column;
  • fxd:crflex-direction:column-reverse;
  • fxd:rflex-direction:row;
  • fxd:rrflex-direction:row-reverse;

justify-content

  • jcjustify-content:;
  • jc:cjustify-content:center;
  • jc:fejustify-content:flex-end;
  • jc:fsjustify-content:flex-start;
  • jc:sajustify-content:space-around;
  • jc:sbjustify-content:space-between;

flex-wrap

  • fxwflex-wrap: ;
  • fxw:nflex-wrap:nowrap;
  • fxw:wflex-wrap:wrap;
  • fxw:wrflex-wrap:wrap-reverse;

align-items

  • aialign-items:;
  • ai:balign-items:baseline;
  • ai:calign-items:center;
  • ai:fealign-items:flex-end;
  • ai:fsalign-items:flex-start;
  • ai:salign-items:stretch;

align-content

  • acalign-content:;
  • ac:calign-content:center;
  • ac:fealign-content:flex-end;
  • ac:fsalign-content:flex-start;
  • ac:salign-content:stretch;
  • ac:saalign-content:space-around;
  • ac:sbalign-content:space-between;

align-self

  • asalign-self:;
  • as:aalign-self:auto;
  • as:balign-self:baseline;
  • as:calign-self:center;
  • as:fealign-self:flex-end;
  • as:fsalign-self:flex-start;
  • as:salign-self:stretch;

order

  • ordorder:;

flex

  • fxflex:;
  • fxbflex-basis:;
  • fxdflex-direction:;
  • fxd:cflex-direction:column;
  • fxd:crflex-direction:column-reverse;
  • fxd:rflex-direction:row;
  • fxd:rrflex-direction:row-reverse;
  • fxfflex-flow:;
  • fxgflex-grow:;
  • fxshflex-shrink:;
  • fxwflex-wrap: ;
  • fxw:nflex-wrap:nowrap;
  • fxw:wflex-wrap:wrap;
  • fxw:wrflex-wrap:wrap-reverse;

外容器屬性

1. 必備屬性

使用 Flexbox 就是要將 display 設為 flexinline-block

  • display: flex 其布局方式與 block 一樣,都會強迫換行;
  • inline-flexinline-block 也 一樣,在後方的元素不會換行。

唯一不同的是,flexinline-flex 的子元素具備了更多彈性的設定。

1
2
3
4
<div class="container">
  <div class="box"></div>
  <div class="text"></div>
</div>
1
2
3
4
5
6
7
8
9
.container {
  display: block;
}

.box {
  display: flex;  /* or inline-flex  */
  width: 100px;
  height: 100px;
}

2. 主軸方向

flex-direction 可以決定主軸的方向,主軸的方向將會影響容器內的元素排序順序、方向。

flex-direction 設定值共有以下四種:

  • row:預設值,由左到右,從上到下
  • row-reverse:與 row 相反
  • column:從上到下,再由左到右
  • column-reverse:與 column 相反
1
2
3
4
5
 <div class="container">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
  </div>
1
2
3
4
5
6
7
8
9
.container {
  display: flex;
  flex-direction: row;
}

.item {
  width: 50px;
  height: 50px;
}

3. 主軸對齊

justify-content 決定了內容元素與整個 Flexbox 的「主軸對齊」位置,設定值共有以下五種:

  • flex-start:預設值,對齊主軸線最前端
  • flex-end:對齊主軸線最終端
  • center:對齊主軸線中央
  • space-between:平均分配寬度,第一項和最後一項貼齊邊緣
  • space-around:平均分配寬度、間距
1
2
3
4
5
 <div class="container">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
  </div>
1
2
3
4
5
6
7
8
9
.container {
  display: flex;
  justify-content: flex-start;
}

.item {
  width: 50px;
  height: 50px;
}

4. 交錯軸對齊

align-items 剛好和 justify-content 相反,align-items 決定了內容元素與整個 Flexbox 的「交錯軸對齊」位置,設定值總共有下列五個:

  • stretch:預設值,如果子元素 height: auto,會將撐開至父元素的高度
  • flex-start:對齊交錯軸線最前端
  • flex-end:對齊交錯軸線最末端
  • center:對齊交錯軸線中央
  • baseline:對齊子元素的基線
1
2
3
4
5
 <div class="container">
    <div class="item"></div>
    <div class="item h100"></div>
    <div class="item h-auto"></div>
  </div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
.container {
  display: flex;
  justify-content: flex-start;
}

.item {
  width: 50px;
  height: 50px;
}

.h-100 {
  height: 100px;
}

.h-auto {
  height: auto;
}

5. 換行

當我們把父容器的 display 設定為 flexinline-flex 的時候,子元素就是以單行的方式排列,因為預設不會行,因此當遇到邊界會彈性調整元素。

flex-wrap 可以調整元素是否換行,共有三個設定值:

  • nowrap:預設值,不斷行
  • wrap:多行
  • wrap-reverse:多行,但主軸線起點與終點相反
1
2
3
4
5
6
 <div class="container">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    ...
  </div>
1
2
3
4
5
6
7
8
9
.container {
  display: flex;
  flex-wrap: nowrap;
}

.item {
  width: 50px;
  height: 50px;
}

6. 多行交錯軸對齊

align-items 是針對內容為單行的子元素進行處理,如果遇到多行的子元素(flex-wrap: wrap),就要使用 align-content 這個屬性,這個屬性總共有六個設定值:

  • stretch:預設值,會平均分配行距,height: auto 會撐開填滿整行。
  • flex-start:對齊交錯軸線最前端
  • flex-end:對齊交錯軸線最末端
  • center:對齊交錯軸線中央
  • space-between:第一行與最後一行分別對齊交錯軸線最上方與最下方
  • space-around:平均分配行距,兩端會有行距一半的間距
1
2
3
4
5
6
 <div class="container">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    ...
  </div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
.container {
  display: flex;
  flex-wrap: wrap;
  align-content: stretch,
}

.item {
  width: 50px;
  height: 50px;
}

內層元素屬性

1. 交錯軸位置

align-self 作用於內層容器,也就是子元素本身,會覆蓋外層容器的 align-items

設定值與 align-items 相同:

  • stretch:預設值,如果子元素 height: auto,會將撐開至父元素的高度
  • flex-start:對齊交錯軸線最前端
  • flex-end:對齊交錯軸線最末端
  • center:對齊交錯軸線中央
  • baseline:對齊子元素的基線
1
2
3
4
5
6
<div class="container">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  ...
</div>
1
2
3
.item {
  align-self: stretch;
}

2. 排序

order 屬性可以直接指定一個數字,就可以由小到大的排列順序。

  • 預設值為 0,只給一個元素設置會跑到最後面
  • 要設置到最前頭,可以設值負值
  • 相同的數字,看元素排序

注意,order 僅僅對元素的視覺順序 (visual order) 產生作用,並不會影響元素的邏輯或順序。

1
2
3
4
5
6
<div class="container">
  <div class="item item1">1</div>
  <div class="item item2">2</div>
  <div class="item item3">3</div>
  <div class="item item4">4</div>
</div>
1
2
3
.item1 {
  order: 2;
}

3. 伸縮比

FlexBox 最重要的屬性「flex」,個別調整子元素長度「伸展」、「壓縮」的比例以及基本大小。

flex 是簡寫,裡面依序包含三個屬性:

  • flex-grow:預設值為 0,負值無效
  • flex-shrink:預設值為 1,負值無效
  • flex-basis:預設值為 auto,若值為 0,則必須加上單位,以免被視作伸縮性
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
/* 單值語法 無單位數值 unitless number: flex-grow */

flex: 2;

/* 單值語法 有效寬高單位 width/height: flex-basis */

flex: 10em;
flex: 30px;

/* 雙值語法 flex-grow | flex-basis */

flex: 2 2;


/* 三值語法 flex-grow | flex-shrink | flex-basis */
flex: 2 2 10%;

三個屬性可以分開設定,也可以合在一起用一個 flex 統一設定。

3.1 伸展比 flex-grow

元素的伸展性,是一個數值,當子元素的寬度「小」於它自己在父元素分配到的寬度,按照數字做相對應的「伸展」比例分配(剩餘空間)。

預設值為 0,不會進行彈性變化,不可為負值,設為 1 則會進行彈性變化。

3.2 壓縮比 flex-shrink

元素收縮性,是一個數值,當子元素的寬度「大」於它自己在父元素分配到的寬度時,會進行壓縮。

預設值為 1,設為 0 的話不會進行彈性變化(全部都 0 可能超出邊界),不可為負值。

3.3 基本大小 flex-basis

flex-basis 為子元素的基本大小,作為父容器的大小比較基準,預設值為 auto

在分配空間之前,子元素會依 flex-basis 或者 width/height,預約空間,剩餘空間會依 flex-grow 分配。

主軸方向 flex-direction

  • 水平 rowflex-basiswidth 的替代
  • 垂直 columnflex-basisheight 的替代

優先級:

  • 如果同時設置,那麼 width/height 會被覆蓋(flex-basis 的優先級較高);
  • 其中有一個是 auto,那麼另外一個非 auto 的屬性優先級會更高。

一些常見問題

一些新手使用 FlexBox,沒注意到的問題。

1. 子元素高度被強制拉伸對齊

常見的情況是,當子元素 col 內,放置不同高度的元素 box,每個子元素 col 都會被強制拉伸對齊。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<div class="container">
  <div class="col">
    <div class="box1"></div>
  </div>
  <div class="col">
    <div class="box2"></div>
  </div>
  <div class="col">
    <div class="box3"></div>
  </div>
</div>
1
2
3
.container {
  display: flex;
}

這是因為 align-items 預設 stretch。因此可以透過改變 align-items 的值解決,或是使用 align-self 個別調整。

2. 元素被壓縮

我們都知道 FlexBox 預設不換行,因此當容器大小不足時,各個子元素會被壓縮。會被壓縮的原因是 flex-shrink 預設為 1

所以如果不希望元素被壓縮,可以將 flex-shrink 設為 0

1
2
3
4
5
6
7
<div class="container">
  <div class="col flex-shrink-0">
    <img src="https://picsum.photos/300/300" alt="">
  </div>
  <div class="col"></div>
  <div class="col"></div>
</div>

竹白
作者
竹白
前端筆記

文章目錄