CSS Flexbox 視覺化手冊

瘋狂的技術宅發表於2019-01-31

翻譯:瘋狂的技術宅 原文:https://medium.com/swlh/css-flexbox-fundamentals-visual-guide-1c467f480dac

介紹

Flexbox是 Flexible Box Module(彈性盒模型)的縮寫。 是一種可以輕鬆控制html元素之間的空間分佈和對齊的佈局模型。

Flexbox同一時間只能控制行或列中的一個維度。對於二維控制需要 CSS 網格佈局。

clipboard.png

首先給出如下模板:

<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

clipboard.png

彈性專案

display: flex 應用於 .container div 時,所有直接子div都變為 flex-items,並獲得新的行為

  • 它們將顯示在同一行中,因為flex-direction預設為row
  • 它們將會從左到右顯示

clipboard.png

  • 其中的專案不會自動伸展來適應整個寬度(主軸),為了做到這一點,它們會縮小。

clipboard.png

  • 專案會被拉伸以適合交叉軸(在此示例中為高度)。 如果這些專案的高度不一致,它們將會伸展到最高的那個高度
  • flex-basis 預設為 auto(專案寬度將由其內容決定)
  • flex-wrap 預設為nowrap(如果容器的寬度不足以適合這些專案,它們不會換行,而是會溢位)

出於視覺化的目的,讓我們拉伸容器使其佔據整個高度。

彈性容器

display:flex 使容器擴充套件至整個可用寬度。 這點與 display:inline-flex 相反,它使容器縮小到內容的寬度。

clipboard.png

彈性方向

一旦被宣告為 flex 容器,就可以認為該元素具有兩個軸:主軸與交叉軸。 主軸由flex-direction屬性定義。 交叉軸垂直於前者。

flex-direction 屬性有四個值:rowrow-reversecolumncolumn-reverse

其預設值為row,它從左到右水平設定主軸,交叉軸從上到下垂直擷取。 類似地, column 值從頂部到底部垂直設定主軸,從左到右設定交叉軸。 這兩個選項的相反屬性使主軸反轉180°。 交叉軸保持不變。

可以通過下圖觀察這些值的 flex-items 行為:

clipboard.png

Flex Wrap

當容器中的空間不足以容納其中的彈性專案時,可以用 flex-wrap 來處理。

在預設情況下,flex-wrap 被設定為 nowrap,這意味著如果容器不能適應在其內的行中原始寬度的專案,則這些專案將會縮小來進行適應。 如果它們因為某種原因無法收縮,則會溢位容器。

把專案寬度設定為300px,nowrap 選項會輸出以下結果:

clipboard.png

其中,每個專案都會縮小到大約 70px 來適合容器。

當屬性被更新為wrap時,現在專案的寬度實際上是原始值300px。 當第一行不足以容納300px時,則該專案將換行到新的一行,而不是溢位容器。 應該把其中的每一行都視為單獨的彈性容器。 一個容器中的空間分佈不會影響到與其相鄰的其他容器。

clipboard.png

但是為什麼彈性專案會佔據整個螢幕高度呢? 在第一部分中,容器高度設定為 100vh ,因此可用空間被平均分為四行,來適合 300px 專案的需要。 如果我們沒有設定 100vh,容器的高度則會遵循專案內容的高度,如下圖所示:

clipboard.png

另一個選項是wrap-reverse,它會反轉交叉軸。 通過 flex-direction 屬性從上到下設定,wrap-reverse 將其轉換為從下到上。

clipboard.png

通過使用 flex-direction:column 反轉主軸,不適應的元素會被換到另一列,剩餘空間被均勻分割。

clipboard.png

wrap-reverse 選項會沿著列方向將交叉軸從右向左反轉,產生以下輸出:

clipboard.png

由於flexbox是單維度佈局,所以在進行反轉時,專案從下到上進行排列(對於行方向),但保持左右結構,只改變了交叉軸。

彈性流

flex-directionflex-wrap 可以在一個屬性當中宣告:flex-flow:[direction][wrap]

.flex-container {
  flex-flow : column wrap;
}複製程式碼

專案之間的縫隙

讓我們回到row/wrap。 可以通過設定專案的 width:33.3333% 來填充整個容器:

clipboard.png

但是如果你希望在子div 之間有一個間隙,它們就不會按照你想的那樣換行:

clipboard.png

這個小麻煩這可以通過 CSS 函式 calc() 來解決:

.flex-item {
  width: calc(33.33333% - 40px);
  margin: 20px;
}複製程式碼

clipboard.png

為了消除容器邊緣的空間,可以在容器上使用負邊距:

.flex-container {
  margin: -20px;
}複製程式碼

clipboard.png

排序

order 屬性允許更改出現的可視排序專案。排序被分配給組。 預設情況下所有的彈性專案都設定為 order: 0,這意味著所有專案都屬於同一組,並且它們將按照原始順序定位。 在兩個或多個組的情況下,組會相對於它們的整數值進行排序。

在下面的例子中,有三個 ordinal groups-1, 01,按此順序進行排列。

.box-3 { order: 1; }
.box-7 { order: 1; }
.box-8 { order: -1; }複製程式碼

clipboard.png

此屬性可視地重新分配專案,但在互動時保持其原始源位置,例如使用Tab鍵遍歷它們。 如果物品訂購對可訪問性有影響,則可以考慮這一點。 flex-direction 也是如此。

clipboard.png

對齊

clipboard.png
(此圖反覆上傳總是出錯,請大家移步原文檢視)

在Flexbox中,沿著軸的專案對齊和空間分佈可以受到四個屬性的控制:

  • justify-content: 對齊主軸中的所有專案
  • align-items: 對齊交叉軸中的所有專案
  • align-self: 對齊交叉軸中的單個專案
  • align-content: 控制交叉軸上柔性線之間的空間

justify-content

clipboard.png

適用於容器,justify-content 處理專案在主軸上的對齊方式。六個最常用的選項包括: flex-startflex-endcenterspace-aroundspace-betweenspace-evenlyflex-start是預設值。.

align-items

clipboard.png

也適用於容器, align-items 屬性處理交叉軸方向上的對齊。它的預設值是 stretch 其它的選項是 flex-startflex-endcenterbaseline

stretch 選項使所有專案伸展到容器高度(如果設定)或最高專案的高度[5]。 第一張圖片顯示容器高度設定為 100vh,未設定第二個高度。

align-content

clipboard.png

這是作用在 flex 容器的四個屬性中的最後一個,align-content 在交叉軸中的彈性線之間分配空格。 作為後者,它的初始值是 stretchjustify-content,它接受以下選項: flex-start, flex-end, center, space-around, space-between, space-evenly

align-self

clipboard.png

align-items 屬性實際上通過在容器內的所有 flex 專案上設定 align-self 來實現。 通過單獨設定 align-self,可以覆蓋全域性值。 它接受與align-items和'auto'相同的值[5]。

auto 選項通過 align-itemsalign-self 重置為容器全域性定義的值。

調整 Flexbox 的大小

專案的尺寸和伸展性可以通過三種屬性來控制: flex-growflex-shrinkflex-basis。 這三個都作用於主軸。

  • flex-grow:如果有額外的空間,每個專案應該如何放大
  • flex-shrink:如果沒有足夠的空間,應該如何縮小每個專案
  • flex-basis:在設定上述兩個屬性之前,該專案的大小應該是多少

flex-grow

由此屬性設定的 flex grow factor (彈性增長因子)用來處理專案大小相對於彼此的比率。

預設值為 0,這意味著如果還有可用空間,就把它放在最後一個專案之後。

clipboard.png

在上面的例子中,direction 被設定為 row,每個彈性專案的 width 被設定為 60px。 由於容器寬是 980px,所以剩餘的可用空間為 680px。 這個空間被稱為positive free space (正自由空間)。

如果將 flex-grow 設定為1,正可用空間量會在彈性專案之間平均分配。 每個專案的寬度將會增加 136px,總寬度為196px

clipboard.png

通過將 flex-grow: 2 應用到第三個專案,它會得到比其它專案多出兩倍的可用正自由空間,即286px,其他專案仍為173px

下圖顯示了把專案的 flex-grow 屬性值設定為其內容對應的數字時的情形。

clipboard.png

flex-shrink

當沒有足夠的可用空間來容納所有容器時,用 flex-shrink 處理專案大小。 它通過縮小這些專案來劃分它們之間的 negative free space (負自由空間)。

下圖顯示的是寬度為 980px 的容器,它容納了5個寬度為 300px的物品。 由於沒有空間容納所需的總寬度 1500px,所以預設的flex shrink factor(彈性收縮係數)的值為1,這樣會使每個專案的寬度均勻縮小到196px

clipboard.png

通過將第三項的比率設定為2,它縮小為其餘專案大小的二分之一。

clipboard.png

本節的最後一張圖顯示了將每個專案的內容值對應的數字設定為 flex-shrink 的值時的情形。

flex-basis

flex-basis 是在實際設定可用空間之前,檢查每個專案本來應具有的大小的屬性。 預設值為 auto,項寬度由 width 屬性顯式設定,或者取其內容寬度。 它也接受畫素值。

下面的動圖顯示了一個800px寬的容器和五個設定為 flex-basis:160px 的彈性專案。 這告訴瀏覽器:如果在理想狀態下,有足夠的空間來放置所有的專案,就遵循它們的160px寬度,並且沒有正/負可用空間;如果沒有足夠的空間的話,那麼 flex-shrink 預設為1,所有專案均勻收縮; 如果有額外的空間,flex-grow 預設為0,並且剩餘的空間放在最後一個專案之後。

clipboard.png

下一個動圖展示了把專案1設定為flex-shrink:10,專案4設定為flex-grow:10。對於負自由空間,專案1的寬度減少10倍。 對於正空閒空間,第4項的寬度是其他空間的10倍。

clipboard.png

flex-basis 也接受值 content,此時無論其寬度是否被設定,計算自由空間時所考慮的寬度依據是專案中的內容。

flex

flex 屬性是按順序排列的 flex-growflex-shrinkflex-basis 的簡寫,它接受以下預定義值:

  • initial:重置為 flexbox 的預設值,等同於 flex: 0 1 auto
  • auto:flex-items能夠根據需要增長/縮小,等同於 flex: 1 1 auto
  • none:固定專案,等同於 flex: 0 0 auto
  • flex: 1:flex-items 具有伸縮的能力,flex-basis 設定為零,等同於 flex: 1 1 0

Autoprefixer

對於跨瀏覽器的相容性問題,設定具有具有必要字首的屬性是非常重要的,以確保能夠支援所有瀏覽器。

手動自動為每個屬性新增字首可能是一項非常繁瑣的任務,也使樣式很難維護。使用 Gulp 能夠替你自動執行這些任務。

為了能夠使用Gulp,我們必須將它作為依賴新增到專案當中。 這項工作是在 package.json 檔案中完成的,它負責跟蹤專案依賴及其版本。 在終端中輸入下列命令來建立檔案:

nmp 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複製程式碼

新增以下內容:

// gulpfile.js

var gulp = require('gulp');
var autoprefixer = require('gulp-autoprefixer');
var options = { browsers: ['last 2 versions'], cascade: false };

gulp.task('styles', function() {
  return gulp.src('./styles.css')
             .pipe(autoprefixer(options))
             .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

本文首發微信公眾號:jingchengyideng,歡迎關注京程一燈公眾號,獲取更多前端技術視訊。


相關文章