起源
2019年1月29日,Chrome72正式版(72.0.3626.81)釋出,本次釋出帶來了一個改變,且沒有在更新日誌中提及,該改變導致某些網站發生了佈局錯亂。該改變主要針對的是巢狀的flex佈局,下面我們一起看下是怎麼回事。
問題
首先,我們有一個巢狀的flex佈局,程式碼如下:
<style>
div {
box-sizing: border-box;
}
.flex {
display: flex;
flex-direction: column;
}
.area {
padding: 10px;
height: 300px;
width: 300px;
background-color: #3fb9ab;
color: #fff;
}
.item {
padding: 10px;
flex: 1;
background-color: #158c7e;
}
.nest-item {
flex: 1;
overflow: auto;
background-color: #046b5f;
}
.content {
padding: 10px;
height: 600px;
}
</style>
<div class="area flex">
area
<div class="item flex">
item
<div class="nest-item">
<div class="content">content</div>
</div>
</div>
</div>
複製程式碼
希望實現這樣的效果:父容器area有一個指定的高度,且它是一個flex彈性盒子,它內部有一個子元素item,使用 flex: 1
指定了佔滿剩餘空間,且item也是一個flex彈性盒子,它內部還有一個同樣佔滿剩餘空間的巢狀子元素nest-item,通過設定 overflow: auto
讓它的內容超出後顯示滾動條。效果如下:
這樣佈局的想法很簡單,即通過設定彈性盒子子元素的擴充套件比率,能得到一個自動佔滿剩餘空間高度的容器,再在這個容器中放需要顯示的內容,在某些情況下,這確實是一個比較不錯的主意,在Chrome72之前都是可以正常顯示的。但是Chrome72.0.3626.81中顯示如下:
追溯
為什麼會出現這樣的問題呢?我們看一下規範( drafts.csswg.org/css-flexbox… )flex彈性盒子主軸上子元素的最小大小是內容的大小(視主軸方向為寬或高)。
那麼我們再看一下上面的例子,area的主軸是縱向的,子元素item的最小高度即是內容的高度,而nest-item被content撐開,content有一個高度(600px,超出了容器的高度),那麼item的最小高度也就超過了600px。這樣一來,一層層都是被內容撐開,也就沒有出現滾動條了,這樣似乎是符合規範預期的。
在chromium的issue反饋中,有人提到了這個問題( bugs.chromium.org/p/chromium/… ),根據回覆,這正是官方為了讓Chrome更加符合規範行為而做的調整。也就是說,Chrome72之前的版本,這算是一個沒有按照規範行為而出現的bug。新的調整,其實就是讓flex彈性盒子的子元素最小高度的預設行為應用 min-height: min-content
,就像官方回覆中提到的那樣,讓子元素作為flex彈性盒子時卻和普通盒子處理方式不同是會讓人困惑的。
解決方法
既然知道了原因,那麼如果我們還想使用這樣的佈局方式,該怎麼做呢?
對的,我們給item指定一個最小高度,讓它不使用預設的行為(即內容的高度),一般我們指定最小高度為0 min-height: 0
。給item加上這個樣式後,我們再看一下效果:
嗯,已經符合我們的預期了。為了驗證規範中提到的對主軸方向的行為,我們修改一下程式碼,將主軸設定為水平方向試試,程式碼如下:
<style>
div {
box-sizing: border-box;
}
.flex {
display: flex;
flex-direction: row;
}
.area {
padding: 10px;
height: 300px;
width: 300px;
background-color: #3fb9ab;
color: #fff;
}
.item {
padding: 10px;
flex: 1;
background-color: #158c7e;
}
.nest-item {
flex: 1;
overflow: auto;
background-color: #046b5f;
}
.content {
padding: 10px;
width: 600px;
}
</style>
<div class="area flex">
area
<div class="item flex">
item
<div class="nest-item">
<div class="content">content</div>
</div>
</div>
</div>
複製程式碼
效果如下:
看來主軸為水平方向時,是符合規範預期行為的(Chrome72及以前的版本都符合),那麼我們給item加上一句樣式 min-width: 0
,效果如下:
嗯,是符合我們預期的。
結語
好了,現在你已經知道是怎麼一回事了,可是等等,你說你升級到Chrome72沒有發現我說的問題?
那是因為官方注意到這個修改會影響到一些網站的正常顯示,因此在2019年2月6日(正是春節假期間)釋出的Chrome72.0.3626.96中,將這個問題還原回以前的行為了( chromium.googlesource.com/chromium/sr… )。
官方的意思是為了避免這個修改給某些網站帶來的不好的影響,因此預留時間給大家修改,等到Chrome73將會發布這一改變。所以為了未來更好的瀏覽體驗,檢查一下你的頁面吧!