flex:0 flex:1 flex:none flex:auto應該在什麼場景下使用?

lu92649264發表於2020-12-11

一、推薦使用flex縮寫語法

CSS官方文件明確推薦flex屬性使用縮寫語法,描述如下所示:

Authors are encouraged to control flexibility using the flex shorthand rather than with its longhand properties directly, as the shorthand correctly resets any unspecified components to accommodate common uses.

大致意思是,建議使用單值縮寫,而不是完整的3個屬性值,因為單值屬性所對應的flex計算值根據開發者日常最常用的使用進行了優化。

這句話很多人並不知道什麼意思,這個說來話長,想想還是講一下吧。

flex屬性是flex-growflex-shrinkflex-basis這3個CSS屬性的縮寫,如果不清楚,可以參見我之前這篇口碑熱文“CSS flex屬性深入理解”。

按照以往的經驗,flex屬性只有一個值的時候,另外預設的值應該使用預設值才對,但是flex屬性並不是這樣的。

我們可以對比CSS border屬性。

CSS border屬性是border-widthborder-styleborder-color這3個CSS屬性的縮寫,當border屬性設定了1個值或2個值的時候,剩下的屬性值一定是預設值,例如:

  • border:2px等同於border:2px none currentColor,也就是此時border-style是預設值noneborder-color的計算值是當前的色值;
  • border:#fff等同於border:medium none #fff,也就是此時border-width是預設值medium
  • border:solid等同於border:medium solid currentColor

使用下面的程式碼可以得到flex-basis預設值是autoflex-grow預設值是0flex-shrink預設值是1

console.log(getComputedStyle(document.body).flexGrow);
console.log(getComputedStyle(document.body).flexShrink);
console.log(getComputedStyle(document.body).flexBasis);

實際執行效果如下:
Chrome和Firefox瀏覽器獲取的flex子屬性的預設值示意

然後再看下flex縮寫屬性的計算值,就會發現不一樣的事情:

  • flex:1等同於flex:1 1 0%flex:1 2等同於flex:1 2 0%,即flex-basis使用的不是預設值auto,而是使用的0%
  • flex:100px等同於flex:1 1 100px,即flex-grow使用的不是預設值0,而是使用的1

這就是上面提到的flex屬性站在實用主義的角度對縮寫屬性的計算值進行了優化。

然後,還有一個重要原因,flex屬性的長語法需要理解深刻,反覆使用才能駕馭,門檻比較好,因此,實際開發,如果可以,建議使用flex縮寫。

常見的flex縮寫有下面這幾個,flex:0flex:1flex:noneflex:auto,那各個CSS宣告應該在什麼場景下使用才正確呢?

 

二、使用flex縮寫語法場景

下表展示了常見的flex屬性單值語法對應的flex計算值,涵蓋了絕大多數的flex屬性的使用場景。

flex單值語法對應的計算值
單值語法等同於備註
flex: initialflex: 0 1 auto初始值,常用
flex: 0flex: 0 0 0%適用場景少
flex: noneflex: 0 0 auto推薦
flex: 1flex: 1 1 0%推薦
flex: autoflex: 1 1 auto適用場景少

1. flex:initial基本表現和適用場景

flex:initial等同於設定flex: 0 1 auto,可以理解為flex屬性的預設值。

該預設值圖形示意如下圖所示。

flex屬性初始值分解示意

其行為表現文字描述為:

flex容器有剩餘空間時尺寸不會增長(flex-grow:0),flex容器尺寸不足時尺寸會收縮變小(flex-shrink:1),尺寸自適應於內容(flex-basis:auto)(行為類似fit-content)。

舉個例子,我們給flex容器設定深紅色的虛線框,如果此時flex子項(設定深天藍色輪廓)的內容都比較少,就會有如下圖所示的效果,剩餘空間依然保留。

flex子項內容較少時候的尺寸表現

相關CSS程式碼和HTML程式碼如下所示:

.container {
    display: flex;
    border: 2px dashed crimson;
}
.container item {
    border: 2px solid deepskyblue;    
}
<div class="container">
    <item>範張</item>
    <item>範鑫</item>
    <item>範旭</item>
    <item>範帥</item>
    <item>範哥</item>
</div>

如果子項內容很多,由於flex-shrink:1,因此,會縮小,表現效果就是文字換行,效果如下圖所示。

flex子項內容較多時候的尺寸表現

 

'initial'是CSS中的一個全域性關鍵字,表示CSS屬性的初始值,通常用來還原已經設定的CSS屬性。因此日常開發不會專門設定flex:initial宣告,但是不設定並不是說flex預設屬性值用的不多。

flex:initial適用場景

flex:initial宣告適用於下圖所示的佈局效果。

適合flex:initial宣告的佈局輪廓圖示意

上圖所示的佈局效果常見於按鈕、標題、小圖示等小部件的排版佈局,因為這些小部件的寬度都不會很寬,水平位置的控制多使用justify-contentmargin-left:auto/margin-right:auto實現。

除了上圖所示的佈局效果外,flex:initial宣告還適用於一側內容寬度固定,另外一側內容寬度任意的兩欄自適應佈局場景,佈局輪廓如圖下圖所示(點點點表示文字內容)。

適合flex:initial宣告的兩欄自適應佈局輪廓圖示意

此時,無需任何其他Flex佈局相關的CSS設定,只需要容器元素設定display:flex即可。

總結下就是那些希望元素尺寸收縮,同時元素內容萬一較多又能自動換行的場景可以不做任何flex屬性設定。

2. flex:0和flex:none的區別和各自適用場景

flex:0等同於設定flex: 0 0 0%flex:none等同於設定flex: 0 0 auto

這兩個值的圖形示意如下圖所示。

flex:0和flex:none分解示意

從上可以看出flex:0flex:none對應的flex-growflex-shrink屬性值均是0,因此兩者都會有如下的行為描述:

元素尺寸不會彈性增大、也不會彈性變小,也就是元素不再具有彈性。

flex-basis:0%flex-basis:auto有什麼區別呢?

  • flex-basis:0%表示固定尺寸是0,由於元素不具有彈性,因此,設定flex:0的元素的最終尺寸表現為最小內容寬度;
  • flex-basis:auto表示固定尺寸由內容決定,由於元素不具有彈性,因此,元素內的內容不會換行。但是,注意,不會換行並不表示設定flex:none的元素最終尺寸表現就是最大內容寬度,如果外部尺寸不足,flex:none有可能實際的尺寸是最小內容尺寸;

舉個例子,設定每個flex子項有足夠多的內容,HTML程式碼如下所示:

<h4>flex:0</h4>
<div class="container flex-0">
    <item>範張範張範張</item>
    <item>範鑫範鑫範鑫</item>
    <item>範旭範旭範旭</item>
    <item>範帥範帥範帥</item>
    <item>範哥範哥範哥</item>
</div>
<h4>flex:none</h4>
<div class="container flex-none">
    <item>範張範張範張</item>
    <item>範鑫範鑫範鑫</item>
    <item>範旭範旭範旭</item>
    <item>範帥範帥範帥</item>
    <item>範哥範哥範哥</item>
</div>

然後對flex子項分別設定flex:0flex:none,CSS程式碼如下所示:

.container {
    display: flex;
}
.flex-0 item {
    flex: 0;
}
.flex-none item {
    flex: none;
}

結果如圖下圖所示:

flex:0和flex:none的佈局效果示意

可以看到應用了flex:0的元素全部高高聳起,一柱擎天,表現為最小內容寬度;而應用了flex:none的元素則無視容器的尺寸限制,直接溢位容器,沒有換行,表現為最大內容寬度。

適合使用flex:0的場景

由於應用了flex:0的元素表現為最小內容寬度,因此,適合使用flex:0的場景並不多,除非元素內容的主體是替換元素,此時文字內容就會庇護在替換元素的寬度下從而不會出現“一柱擎天”的排版效果。

該適用場景的佈局示意如下圖所示。

適用於flex:0的佈局輪廓示意圖

其中上圖左側部分的矩形表示一個影像,影像下方會有文字內容不定的描述資訊,此時,左側內容就適合設定flex:0,這樣,無論文字的內容如何設定,左側內容的寬度都是影像的寬度。

適合使用flex:none的場景

當flex子項的寬度就是內容的寬度,且內容永遠不會換行,則適合使用flex:none,這個場景比flex:0適用的場景要更常見。

例如列表右側經常會有一個操作按鈕,對於按鈕元素而言,裡面的文字內容一定是不能換行的,此時,就非常適合設定flex:none,例如下面這個例子,示意了按鈕使用了flex:none之後的佈局變化,HTML和CSS程式碼如下所示:

<div class="item">
    <img src="1.jpg">
    <p>右側按鈕沒有設定flex:none,表現為最小內容寬度。</p>
    <button>按鈕</button>
</div>
<div class="item">
    <img src="1.jpg">
    <p>右側按鈕設定了flex:none,按鈕正常顯示了。</p>
    <button class="none">按鈕</button>
</div>
.container {
    display: flex;
    padding: .5rem;
    border: 1px solid lightgray;
    background-color: #fff;
}
img {
    width: 3rem; height: 3rem;
    margin-right: .5rem;
}
button {
    align-self: center;
    padding: 5px;
    margin-left: .5rem;
}
.none {
    flex: none;
}

從程式碼可以看出兩段內容的唯一區別就是下面的佈局對按鈕元素設定了flex:none,結果就有如下圖所示的不同的佈局效果。

適用於flex:none的對比效果示意圖

不僅按鈕正常顯示了,整個佈局會自動適配按鈕的尺寸,也就是按鈕文字多了,中間的文字內容寬度就會自動減小,整個佈局依然是彈性的。

3. flex:1和flex:auto的區別和各自適用場景

flex:1等同於設定flex: 1 1 0%flex:auto等同於設定flex: 1 1 auto

這兩個值的圖形示意如下圖所示。

flex:1和flex:auto分解示意

結合flex屬性值的描述,我們可以得出flex:1flex:auto的行為表現:

元素尺寸可以彈性增大,也可以彈性變小,具有十足的彈性,但是flex:1在尺寸不足時會優先最小化內容尺寸,flex:auto在尺寸不足時會優先最大化內容尺寸。

上面的描述可以通過一個例子明白是什麼意思,這一次是僅僅設定第1項的文字內容很多,HTML程式碼如下所示:

<h4>flex:1</h4>
<div class="container flex-1">
    <item>範張範張範張範張範張範張範張範張範張</item>
    <item>範鑫</item>
    <item>範旭</item>
    <item>範帥</item>
    <item>範哥</item>
</div>
<h4>flex:auto</h4>
<div class="container flex-auto">
    <item>範張範張範張範張範張範張範張範張範張</item>
    <item>範鑫</item>
    <item>範旭</item>
    <item>範帥</item>
    <item>範哥</item>
</div>

可以看出兩段HTML結構和內容都是一樣的,現在,對上下兩端HTML設定不同的CSS樣式,程式碼如下所示:

.flex-1 item {
    flex: 1;
}
.flex-auto item {
    flex: auto;
}

結果就會看到如下圖所示的佈局效果。

flex:1和flex:auto的對比效果示意

上圖鮮明地體現了flex:1flex:auto的區別,雖然都是充分分配容器的尺寸,但是flex:1的尺寸表現更為內斂(優先犧牲自己的尺寸),flex:auto的尺寸表現則更為霸道(優先擴充套件自己的尺寸)。

從某種程度上講,flex:1的表現神似table-layout:fixedflex:auto的表現神似table-layout:auto

適合使用flex:1的場景

當希望元素充分利用剩餘空間,同時不會侵佔其他元素應有的寬度的時候,適合使用flex:1,這樣的場景在Flex佈局中非常的多。

例如所有的等分列表,或者等比例列表都適合使用flex:1或者其他flex數值,適合的佈局效果輪廓如下圖所示。

flex:1適合用在固定比例的列表中

以及適用於無規律佈局中動態內容元素,我們不妨繼續使用flex:none那裡演示的例子進行說明。

下面這段HTML和CSS程式碼下的按鈕元素是換行顯示的(就是前面出現過的按鈕不換行的例子的HTML程式碼)。

<div class="item">
    <img src="1.jpg">
    <p>右側按鈕沒有設定flex:none,表現為最小內容寬度。</p>
    <button>按鈕</button>
</div>
.container {
    display: flex;
    padding: .5rem;
    border: 1px solid lightgray;
    background-color: #fff;
}
img {
    width: 3rem; height: 3rem;
    margin-right: .5rem;
}
button {
    align-self: center;
    padding: 5px;
    margin-left: .5rem;
}

除了設定<button>元素flex:none以外,在這個例子中,我們還可以設定<p>元素flex:1實現類似的效果。

p {
    flex: 1;
}

結果就有如下圖所示,<p>元素設定了flex:1之後,按鈕元素正常顯示了。

主體動態的文字元素設定flex:1之後的效果對比示意

適合使用flex:auto的場景

當希望元素充分利用剩餘空間,但是各自的尺寸按照各自內容進行分配的時候,適合使用flex:auto

flex:auto多用於內容固定,或者內容可控的佈局場景,例如導航數量不固定,每個導航文字數量也不固定的導航效果就適合使用flex:auto效果來實現,我做了個很簡單的示意,程式碼如下所示:

<nav class="flex">
  <span>首頁</span>
  <span>排行榜</span>
  <span>我的訂單</span>
  <span>個人中心</span>
</nav>
nav span {
    flex: auto;
    line-height: 3rem;
    background: #444;
    color: #fff;
    text-align:center;
}
span + span {
    border-left: 1px solid #eee;
}

此時大家就可以看到一個基於內容自動分配寬度的自適應導航效果了,效果如下圖所示,文字越多的導航佔據的寬度越大,這完全是瀏覽器自動分配的。

flex:auto實現的基於內容寬度自動分配的導航效果示意

三、最後總結一下

最後總結一下:

  • flex:initial表示預設的flex狀態,無需專門設定,適合小控制元件元素的分佈佈局,或者某一項內容動態變化的佈局;
  • flex:0適用場景較少,適合設定在替換元素的父元素上;
  • flex:none適用於不換行的內容固定或者較少的小控制元件元素上,如按鈕。
  • flex:1適合等分佈局;
  • flex:auto適合基於內容動態適配的佈局;

以上就是本文內容,寫於2020年國慶,部分內容節選自明年會出版的新書《CSS新世界》。

感謝您的閱讀,如果您覺得本文內容還不錯,歡迎分享。

相關文章