[譯] 讀完 flexbox 細則之後學到的 11 件事

Xat_MassacrE發表於2017-06-14

讀完 flexbox 細則之後學到的 11 件事

在經歷了多年的浮動佈局和清除浮動的折磨之後,flexbox 就像新鮮空氣一般,使用起來是如此的簡單方便。

然而最近我發現了一些問題。當我認為它不應該是彈性的時候它卻是彈性的。修復了之後,別的地方又出問題了。再次修復之後,一些元素又被推到了螢幕的最右邊。這到底是什麼情況?

當然了,最後我把它們都解決了,但是黃花菜都涼了而且我的處理方式也基本上沒什麼規範,就好像那個砸地鼠的遊戲,當你砸一個地鼠的時候,另一個地鼠又冒出來,很煩。

不管怎麼說,我發現要成為一個成熟的開發者並且真正地學會 flexbox 是需要花時間的。但是不是再去翻閱另外的 10 篇部落格,而是決定直接去追尋它的源頭,那就是閱讀 The CSS Flexible Box Layout Module Level 1 Spec

下面這些就是我的收穫。

1. Margins 有特別的功能

我過去常常想,如果你想要一個 logo 和 title 在左邊,sign in 按鈕在右邊的 header ...

[譯] 讀完 flexbox 細則之後學到的 11 件事

點線為了更清晰

... 那麼你應該給 title 的 flex 屬性設定為 1 就可以把其他的條目推到兩頭了。

.header {
  display: flex;
}
.header .logo {
  /* nothing needed! */
}
.header .title {
  flex: 1;
}
.header .sign-in {
  /* nothing needed! */
}複製程式碼

這就是為什麼說 flexbox 是個好東西了。看看程式碼,多簡單啊。

但是,從某種角度講,你並不想僅僅為了把一個元素推到右邊就拉伸其他的元素。它有可能是一個有下劃線的盒子,一張圖片或者是因為其他的什麼元素需要這樣做。

好訊息!你可以不用說“把這麼條目推到右邊去”而是更直接地給那個條目定義 margin-left: auto,就像 float: right

舉個例子,如果左邊的條目是一張圖片:

[譯] 讀完 flexbox 細則之後學到的 11 件事

我不需要給圖片使用任何的 flex,也不需要給 flex 容器設定 space-between,只需要給 'Sign in' 按鈕設定 margin-left: auto 就可以了。

.header {
  display: flex;
}
.header .logo {
  /* nothing needed! */
}
.header .sign-in {
  margin-left: auto;
}複製程式碼

你或許會想這有一點鑽空子,但是並不是,在 概述 裡面這個方法就是用來將一個 flex 條目推到 flexbox 的末端的。它甚至還有自己單獨的章節,使用 auto margins 對齊

哦對了,我應該在這裡新增一個說明,在這篇部落格中我會假設所有的地方都設定了 flex-direction: row。但是對於 row-reversecolumncolumn-reverse 也都是適用的。

2. min-width 問題

你或許會想一定有一個直截了當的方法確保在一個容器中所有的 flex 條目都適應地收縮。當然了,如果你給所有的條目設定 flex-shrink: 1,這不就是它的作用嗎?

還是舉例說吧。

假設你有很多的 DOM 元素來顯示出售的書籍並且有個按鈕來購買它。

[譯] 讀完 flexbox 細則之後學到的 11 件事

(劇透:蝴蝶最後死了)

你已經用 flexbox 安排地很好了。

.book {
  display: flex;
}
.book .description {
  font-size: 30px;
}
.book .buy {
  margin-left: auto;
  width: 80px;
  text-align: center;
  align-self: center;
}複製程式碼

(你想讓 'Buy now' 按鈕在右邊,即使是很短的標題的時候,那麼你就要給他設定 margin-left: auto。)

這個標題太長了,所以他佔用了儘可能多的空間,然後換到了下一行。你很開心,生活真美好。你洋洋得意地將程式碼釋出到生產環境並且自信地認為沒有任何問題。

然後你就會得到一個驚喜,但不是好的那種。

一些自命不凡的作者在標題中用了一個很長的單詞。

[譯] 讀完 flexbox 細則之後學到的 11 件事

那就完了!

如果那個紅色的邊框代表手機的寬度,並且你隱藏了溢位,那麼你就失去你的 'Buy now' 按鈕。你的轉換率,可憐的作者的自我感覺都會遭殃。

(注:幸運的是我工作的地方有一個很棒的 QA 團隊,他們維護了一個擁有各種類似於這樣的令人不爽的文字的資料庫。也正是這個問題特別的促使我去閱讀這些細則。)

就像圖片展示的那樣,這樣的表現是因為描述條目的 min-width 初始被設定為 auto,在這種情況下就相當於 Electroencephalographically 這個單詞的寬度。這個 flex 條目就如它的字面意思一樣不允許被任何的壓縮。

那麼解決辦法是什麼呢?重寫這個有問題的屬性,將 min-width: auto 改為 min-width: 0,給 flexbox 指明瞭對於這個條目可以比它裡面的內容更窄。

這樣就可以在條目裡面處理文字了。我建議包裹單詞。那麼你的 CSS 程式碼就會是下面這個樣子:

.book {
  display: flex;
}
.book .description {
  font-size: 30px;
  min-width: 0;
  word-wrap: break-word;
}
.book .buy {
  margin-left: auto;
  width: 80px;
  text-align: center;
  align-self: center;
}複製程式碼

這樣的結果就是這個樣子:

[譯] 讀完 flexbox 細則之後學到的 11 件事

重申一下,min-width: 0 不是什麼為了特定結果取巧的技術,它是細則中建議的行為

下個章節我會處理儘管我明確寫明瞭但是 ‘Buy now’ 按鈕仍然不總是 80px 寬的問題。

3. flexbox 作者的水晶球

就像你知道的,flex 屬性其實是 flex-growflex-shrinkflex-basis 的簡寫。

我必須承認為了達到我想要的效果,我在不停地嘗試和驗證這三個屬性上面花費了很多時間。

但是直到現在我才明白,我其實只是需要這三者的一個組合。

  • 如果我想當空間不夠的時候條目可以被壓縮,但是不要伸展,那麼我們需要:flex: 0 1 auto
  • 如果我的條目需要儘可能地填滿空間,並且空間不夠時也可以被壓縮,那麼我們需要:flex: 1 1 auto
  • 如果我們要求條目既不伸展也不壓縮,那麼我們需要:flex: 0 0 auto

我希望你還不是很驚奇,因為還有讓你更驚奇的。

你看,Flexbox Crew (我通常認為 flexbox 團隊的皮衣是男女都能穿的尺寸)。對,Flexbox Crew 知道我用得最多的就是這三個屬性的組合,所以他們給予了這些組合 對應的關鍵字

第一個場景是 initial 的值,所以並不需要關鍵字。flex: auto 適用於第二種場景,flex: none 是條目不伸縮的最簡單的解決辦法。

早就該想到它了。

它就好像用 box-shadow: garish 來預設表示 2px 2px 4px hotpink,因為它被認為是一個 ‘有用的預設值’。

讓我們再回到之前那個醜陋的圖書的例子。讓我們的 'Buy now' 按鈕更胖一點...

[譯] 讀完 flexbox 細則之後學到的 11 件事

... 我只要設定 flex: none

.book {
  display: flex;
}
.book .description {
  font-size: 30px;
  min-width: 0;
  word-wrap: break-word;
}
.book .buy {
  margin-left: auto;
  flex: none;
  width: 80px;
  text-align: center;
  align-self: center;
}複製程式碼

(是的,我可以設定 flex: 0 0 80px; 來節省一行 CSS。但是設定為 flex: none可以更清楚地表示程式碼的語義。這對於那些忘記這些程式碼是如何工作的人來說就友好多了。 )

4. inline-flex

坦白講,幾個月前我才知道 display: inline-flex 這個屬性。它會代替塊容器建立一個內聯的 flex 容器。

但是我估計有 28% 的人還不知道這件事,所以現在你就不是那 28% 了。

5. vertical-align 不會對 flex 條目起作用

或者這件事我並不是完全的懂,但是從某種意義上我可以確定,當使用 vertical-align: middle 來嘗試對齊的時候,它並不會起作用。

現在我知道了,細則裡面直接寫了,vertical-align 在 flex 條目上不起作用” (注意:就好像 float 一樣)。

6. margins 和 padding 不要使用 %

這並不僅僅是一個最佳實踐,它類似於外婆說的話,去遵守就好了,不要問為什麼。

"開發者們在 flex 條目上使用 paddings 和 margins 時,應該避免使用百分比" — 愛你的,flexbox 細則。

下面是我在細則裡面看到的最喜歡的一段話。

註解:這個變化糟透了,但是它精準地抓住了世界的當前狀態(實現無定法,CSS 無定則)

當心,糖衣炮彈進行中。

7. 相鄰的 flex 條目的邊緣不會塌陷

你或許知道有時候會出現相鄰條目的邊緣塌陷。你或許也知道其他的時候不會出現邊緣塌陷。

現在我們都知道相鄰的 flex 條目是不會發生邊緣塌陷的。

8. 即使 position: static,z-index 也會有效

我不確定我是否真的在乎這一點。但是我想到或許有一天,它就會真地有用。就好像我冰箱裡有一瓶檸檬汁。

某一天我家來了其他人,然後他會問:"嗨,你這裡有檸檬汁嗎?",我這時就會告訴他:"有的,就在冰箱裡",他會接著說:"謝謝,大兄弟。那麼如果我想給一個 flex 條目設定 z-index,我需要指定 position 嗎?",我會說:"兄弟,不需要,flex 條目不需要這樣。"

9. Flex-basis 是精細且重要的

一旦 initialautonone 都不能滿足你的需求時,事情就有點複雜了,但是我們 flex-basis,有趣的是,你知道的,我不知道怎麼結束這句話。如果你們有好的建議的話,歡迎留言。

如果你有 3 個 flex 條目,它們的 flex 值分別為 3,3 和 4。那麼當 flex-basis0 的話它們就會忽略他們的內容,佔據可用空間的 30%,30%,40%。

然而,如果你想要 flex 更友好但是有點不太可預測的話,使用 flex-basis: auto。這個會將你的 flex 的值設定得更合理,同時也會考慮到一些其他因素,然後為你給出相對合理的寬度。

看看這個很棒的示意圖。

[譯] 讀完 flexbox 細則之後學到的 11 件事

我十分確定我讀到的關於 flex 的部落格中至少有一篇提到了這一點,但是我也不知道為什麼,直到我看到上面這張圖才想起來。

10. align-items: baseline

如果我想讓我的 flex 條目垂直對齊,我總是使用 align-items: center。但是就像 vertical-align一樣,這樣當你的條目有不同的字型大小並且你希望它們基於 baselines 對齊的時,你需要設定 baseline 才能對齊的更完美。

align-self: baseline 也可以,或許更直觀。

11. 我很蠢

下面這段話不論我讀幾遍,都無法理解它的含義...

在主軸上內容大小是最小內容大小的尺寸,並且是加緊的,如果它有一個寬高比,那麼任何定義的 min 和 max 的大小屬性都會通過寬高比轉換,並且如果主軸的 max 尺寸是確定的話會進一步加緊。

這些單詞通過我的眼睛被轉化成電訊號穿過我的視神經,剛剛抵達的時候就看到我的大腦開啟後門一溜煙跑了。

就像米老鼠和瘋狂麥克斯 7 年前生了個孩子,現在和薄荷酒喝醉了,使用他從爸爸媽媽吵架時學到的語言肆意的辱罵周圍的人。

女士們,先生們,我已經放棄了體面開始胡言亂語了,這意味著你可以關閉這篇文章了(如果你看這個是為了學習的話你可以在這裡停止了)。

讀這篇細則我學到的最有趣的事情是,儘管我看過大量的博文,以及 flexbox 也算是相對簡單的知識點,但是我對其的瞭解曾是那麼的不徹底。事實證明 '經驗' 不總是起作用的。

我可以很開心的說花時間來閱讀這些細則已經得到了回報。我已經優化的我的程式碼,設定了 auto margins,flex 的值也設定成了 auto 或者 none,並在需要的地方定義了 min-width 為 0。

現在這些程式碼看起來好多了,因為我知道這樣做是正確的。

我的另外一個收穫就是,儘管這些細則在某些方面正如我所想的基於編者視角並有些龐雜,但是仍然有有很多友好的說明和例子。甚至還高亮了那些初級開發者容易忽略的部分。

然而,這個是多餘的,因為我已經告訴了你所有有用知識點,你就不用再自己去閱讀了。

現在,如果你們要求,那麼我會再去閱讀所有其他的 CSS 細則。

PS:我強烈建議讀讀這個,一個瀏覽器 flexbox bugs 的清單:github.com/philipwalto….


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOSReact前端後端產品設計 等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃

相關文章