- 原文地址:Flexbox Fundamentals
- 原文作者:Marina-ferreira
整理自 MDN web docs 的筆記,同時參考了 Web Bos 上的什麼是 Flexbox系列視訊。
介紹
Flexbox 是 Flexible Box Module
的縮寫。 它是一種佈局模型,允許我們方便地控制 html 元素之間的空間分佈和對齊 [2]。
Flexbox 一次只能控制一個維度的定位(行或者列)。二維定位的控制需要依靠網格佈局 [2]。
給出以下模板:
<body>
<div class="container">
<div class="box box-1">1</div>
<div class="box box-2">2</div>
<div class="box box-3">3</div>
<div class="box box-4">4</div>
<div class="box box-5">5</div>
<div class="box box-6">6</div>
<div class="box box-7">7</div>
<div class="box box-8">8</div>
<div class="box box-9">9</div>
<div class="box box-10">10</div>
</div>
</body>
上面 div 的行為預設遵循正常的 html 文件流,因此從上到下、從左到右進行渲染,並且會佔據整個 body 的寬度,因為它們的 display
屬性預設是 block
。
彈性專案
當為 .container
div 設定 display: flex
時,所有的直接子 div 將成為彈性專案,並且獲得新的行為 [2]:
- 由於
flex-direction
預設值為row
,因此它們會呈一行排列 - 它們將會從左到右排列
- 專案不會依靠伸展來適應整個寬度(主軸),相反,它們採用收縮的方式
- 專案將會伸展以適應交叉軸(在這個例子中是高度)。如果各個專案的高度不同,它們將會伸展至與最高的那個專案等高。
-
flex-basis
預設值為auto
(專案寬度將取決於其自身的內容) -
flex-wrap
預設值為nowrap
(如果容器的寬度不足以囊括所有的專案,則專案不會換行,只會溢位)
出於視覺化的目的,我們拉伸容器以佔據整個高度。
彈性容器
display: flex
使容器擴充整個可用寬度;與之相對的,display: inline-flex
使容器寬度塌陷至與內容寬度相等。
彈性方向
一旦宣告為彈性容器,我們就可以將元素看作位於兩條軸中。一條是由 flex-direction
定義的主軸,一條是與前者垂直的交叉軸 [2]。
flex-direction
屬性有四個值: row
, row-reverse
, column
和 column-reverse
.
預設值是 row
,它將主軸設定為從左到右的水平方向,而交叉軸從上到下與之垂直相交。同理,column
將主軸設定為從上到下的垂直方向,而交叉軸則是從左到右。對這兩個值新增 reverse
,則主軸將反轉 180°,而交叉軸保持不變 1。
可以通過下圖觀察這些值對應的彈性專案行為:
彈性換行
當容器空間不足以容納全部彈性專案時,利用 flex-wrap
屬性處理彈性專案 [3]。
flex-wrap
的預設值為 nowrap
,這意味著如果容器不能在保留專案原始寬度的同時將它們排列成一行的話,專案將會收縮以進行適應。如果由於某些原因無法收縮,則專案會溢位容器外 1。
通過給專案設定 300px 的寬度,nowrap
選項輸出下面這個結果:
其中,每個專案收縮到大約 70px 以適應容器。
當屬性值更新為 wrap
時,專案的寬度將等於原先的值,300px。當第一行的寬度不足以容納 300px 時,專案不再溢位容器外,而是會換行 [3]。每一行都應該被視為是一個獨立的彈性容器,任何一個容器內的空間分佈均不會影響與之相鄰的其他容器 [2]。
但是為什麼彈性專案會佔據整個螢幕的高度呢?在第一部分,容器高度被設定為 100vh,因此可用空間被這四行平分以適應 300px 的專案。假如我們沒有設定 100vh,則容器高度將等於專案內容的高度,如下圖所示 [1]:
另一個選項是 wrap-reverse
,它將會反轉交叉軸。通過屬性 flex-direction
設定的從上到下的方向會被 wrap-reverse
轉化為從下到上 [1]。
通過 flex-direction: column
反轉主軸,容納不下的元素將會換行至另一列,同時剩餘空間會被平分 [1]。
wrap-reverse
選項與 column
方向搭配使用,則將反轉交叉軸的方向為從右到左,產生如下輸出:
彈性佈局是一維佈局,雖然在反轉換行的時候,專案會從下到上排列(在方向為 row 的情況下),但是依然保持著從左到右的結構。改變的只有交叉軸。
彈性流
flex-direction
和 flex-wrap
可以在一個單屬性中進行宣告: flex-flow: [direction] [wrap]
[2]。
.flex-container {
flex-flow : column wrap;
}
專案之間的空隙
回到主軸方向為 row 且進行換行的情況。通過給專案設定 width: 33.3333%
,容器能夠完全被填滿。
但是當你讓子 div 之間有空隙時,它們將不會像預期的那樣進行換行:
可以通過使用 CSS 函式 calc()
解決這個問題 [1]:
.flex-item {
width: calc(33.33333% - 40px);
margin: 20px;
}
為了消除容器邊緣的空間,這裡對容器設定負外邊距 [3]:
.flex-container {
margin: -20px;
}
順序
order
屬性允許修改專案的呈現順序。順序是以組為單位進行分配的。預設情況下所有的彈性專案都設定為 order:0
,這意味著所有的專案位於同一組,並且它們會按照原始順序進行定位。如果有兩個或者兩個以上的組,那麼各組將會相對於它們的整數值進行排序 [4]。
在下面的例子中,有三個順序組
, -1
, 0
和 1
,它們按照如下順序排列。
.box-3 { order: 1; }
.box-7 { order: 1; }
.box-8 { order: -1; }
表面上,這個屬性重新分配了專案,但在諸如使用 tab 鍵對它們進行遍歷的互動中則依然保留它們的原始位置。如果專案順序與可訪問性有關的話,這一點是需要考慮的。同理, flex-direction
也是這樣 [4]。
對齊
在彈性佈局中,沿著軸的專案對齊和空間分佈可以通過四個屬性控制 [5]:
-
justify-content
:將所有專案在主軸上對齊 -
align-items
:將所有專案在交叉軸上對齊 -
align-self
:將單個專案在主軸上對齊 -
align-content
:控制交叉軸上各條線之間的空間
justify-content
justify-content
是一個在主軸上處理專案的容器屬性。最常用的 6 個值是: flex-start
, flex-end
, center
, space-around
, space-between
, space-evenly
。其中,預設值為 flex-start
。
align-items
align-items
同樣是一個容器屬性,它在交叉軸上處理專案的對齊。 預設值是 stretch
,其他值是 flex-start
, flex-end
, center
和 baseline
[5]。
如果設定了容器高度,則 stretch
屬性值會使所有的專案伸展至與容器等高;如果沒有設定,則所有專案與最高的專案等高 [5]。上面第一張圖片中容器高度設定為 100vh
,第二張圖片則沒有設定高度。
align-content
align-content
是第四個也是最後一個容器屬性,它在交叉軸上分配各條線之間的空間。作為最後一個屬性,它的初始值為 stretch
,並且和 justify-content
一樣接受以下幾個屬性值:flex-start
, flex-end
, center
, space-around
, space-between
, space-evenly
[5]。
align-self
align-items
屬性實際上是通過給容器內的所有專案設定 align-self
而生效的。通過單獨設定 align-self
,可以覆蓋先前設定的總的屬性值。該屬性和 align-items
擁有相同的可選值,但是還多了一個 ‘auto’ [5]。
auto
會重置 align-self
的值,使之重新等於通過 align-items
給容器全域性定義的值 [5]。
彈性專案大小
專案的大小和彈性可以通過三個屬性控制:flex-grow
,flex-shrink
和 flex-basis
。這些屬性都在主軸上發揮作用 [2]。
-
flex-grow
:如果有額外空間,每個專案應該如何伸展 -
flex-shrink
:如果空間不足,每個專案應該如何收縮 -
flex-basis
:在設定以上兩個屬性之前專案的大小
flex-grow
該屬性設定的是彈性增長係數
,這是一個用於處理專案之間相對大小的比率 [7]。
預設值是 0,這意味著如果有剩餘空間,就把這個空間放在最後一個專案的後面 [1]。
在上面的例子中,direction
設定為 row
,每個彈性專案的寬度是 60px
。由於容器的寬度是 980px
,因此有 680px
的可用空間,這個空間稱為 正向自由空間
[7]。
通過將 flex-grow
設定為 1
,正向自由空間將會被彈性專案平分。每個專案的寬度都會增加 136px
,總的寬度是 196px
[7]。
通過給第三個專案設定 flex-grow: 2
,它獲得的可用正向自由空間是其他專案的兩倍,即比起其他專案的 173px
,它的總寬度為 286px
[7]。
下圖中,專案的 flex-grow
屬性設定為自身的內容值。
flex-shrink
當容器沒有足夠空間來容納所有專案時,使用 flex-shrink
處理專案大小。因此,它通過收縮專案來處理它們的負向自由空間 [7]。
如下圖所示,980px
的容器存放著 5 個 300px
寬度的容器。由於沒有足夠空間來容納所需要的 1500px
,預設的彈性收縮係數
1
會使每個專案收縮至 196px
。
通過給第三個專案設定 2
的比率,它會比其它專案小兩倍。
下圖中,每個專案以自身內容值作為彈性收縮比率。
flex-basis
flex-basis
屬性會在實際設定可用空間之前檢查每個專案應該具有的大小。預設值是 auto
,專案寬度要麼通過 width
顯式設定,要麼等於內容寬度。它同樣也接受畫素值 [7]。
下面的 gif 展示了一個 800px
寬度的容器和 5 個設定了 flex-basis: 160px
的彈性專案。這告訴瀏覽器:理想情況下有足夠的空間放置所有的專案,專案的 160px
寬度將會得到保留,並且沒有正向/負向自由空間。如果沒有足夠的空間,由於 flex-shrink
預設為 1
,所有的專案會均勻地收縮。如果有剩餘的空間,由於 flex-grow
預設為 0
,剩餘空間會放置在最後一個專案的後面。
下面的 gif 中,專案 1 設定為 flex-shrink: 10
,專案 4 設定為 flex-grow: 10
。對於負向自由空間,專案 1 減小的寬度是其它專案減小寬度的 10 倍;對於正向自由空間,專案 4 增加的寬度是其它專案增加寬度的 10 倍。
flex-basis
還可以接受值 content
。此時,無論有沒有設定 width
,自由空間計算都只會基於專案內容去計算寬度。如果你不打算在計算時考慮專案寬度,則將其設定為 0
。
flex
flex
是 flex-grow
, flex-shrink
和 flex-basis
的簡寫屬性 [2]。
它接受下面的預定於值:
-
initial
:重置為彈性佈局的預設值,與 flex: 0 1 auto 效果一樣 -
auto
:彈性專案可以根據需要伸展/收縮,與 flex: 1 1 auto 效果一樣 -
none
:使專案失去彈性,與 flex: 0 0 auto 效果一樣 -
flex: 1
:彈性專案可以伸展/收縮,並且flex-basis
設定為 0 ,與 flex: 1 1 0 效果一樣
Autoprefixer
考慮到跨瀏覽器相容性,給屬性加上所有必要的字首很重要,這可以確保提供全面的支援 [1]。
手動給每個屬性新增字首是一項非常繁瑣的任務,並且還會徒增樣式維護的難度。作為替代方法,Gulp 可以自動化地完成這些任務。
要使用 Gulp,我們需要將其作為依賴項新增到專案中。這是通過 package.json
檔案完成的,它負責跟蹤依賴項及其版本。通過終端建立檔案型別 [1]:
? npm init
在提示下輸入資訊,點選Enter鍵進行確認。輸出檔案大概類似下面這樣:
{
"name": "project-name",
"version": "1.0.0",
"description": "Project description",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Author Name",
"license": "ISC"
}
全域性安裝 gulp :
? npm install gulp -g
安裝 gulp 和 gulp-autoprefixer 作為專案的依賴性:
? npm install gulp --save-dev
? npm install gulp-autoprefixer --save-dev
它們會出現在 package.json
檔案的 devDependencies
鍵下。
建立一個 gulpfile.js
檔案:
? touch gulpfile.js
新增下面內容 [9]:
//gulpfile.js
var gulp = require('gulp');
var autoprefixer = require('gulp-autoprefixer');
gulp.task('styles', function() {
return gulp.src('./styles.css')
.pipe(autoprefixer({ browsers: ['last 2 versions'], cascade: false }))
.pipe(gulp.dest('build'));
});
gulp
從 styles.css
中提取內容並通過 gulp-autoprefixer
進行傳遞。輸出檔案保留在 build
資料夾下。
引用
- [1] What the Flexbox Course
- [2] Basic concepts of flexbox - 25/03/2018
- [3] Mastering Wrapping of Flex Items - 26/03/2018
- [4] Ordering Flex Items - 26/03/2018
- [5] Aligning Items in a Flex Container - 26/03/2018
- [6] StackOverflow - 27/03/2018
- [7] Controlling Ratios of Flex Items Along the Main Axis - 28/03/2018
- [8] Gulp
- [9] Gulp Autoprefixer
譯者注:
彈性專案:Flex Items
彈性容器:Flex Container
彈性方向:Flex Direction
彈性換行:Flex Wrap
彈性流:Flex Flow
彈性專案大小:Flexbox Sizing