起源
2019 年 1 月 29 日,Chrome72 正式版(72.0.3626.81)發布,本次發布帶來了一個改變,且沒有在更新日志中提及,該改變導致某些網站發生了布局錯亂。該改變主要針對的是嵌套的flex布局,下面我們一起看下是怎么回事。
問題
首先,我們有一個嵌套的 flex 布局,代碼如下:
area
item
content
希望實現這樣的效果:父容器 area 有一個指定的高度,且它是一個 flex 彈性盒子,它內部有一個子元素 item,使用 flex:1 指定了占滿剩余空間,且 item 也是一個 flex 彈性盒子,它內部還有一個同樣占滿剩余空間的嵌套子元素 nest-item,通過設置 overflow:auto 讓它的內容超出后顯示滾動條。效果如下:

這樣布局的想法很簡單,即通過設置彈性盒子子元素的擴展比率,能得到一個自動占滿剩余空間高度的容器,再在這個容器中放需要顯示的內容,在某些情況下,這確實是一個比較不錯的主意,在 Chrome72 之前都是可以正常顯示的。但是 Chrome72.0.3626.81中顯示如下:

追溯
為什么會出現這樣的問題呢?我們看一下規范( https://drafts.csswg.org/css-flexbox/#min-size-auto )flex 彈性盒子主軸上子元素的最小大小是內容的大小(視主軸方向為寬或高)。
那么我們再看一下上面的例子,area 的主軸是縱向的,子元素 item 的最小高度即是內容的高度,而 nest-item 被 content 撐開,content 有一個高度(600px,超出了容器的高度),那么 item 的最小高度也就超過了 600px。這樣一來,一層層都是被內容撐開,也就沒有出現滾動條了,這樣似乎是符合規范預期的。
在 chromium 的 issue 反饋中,有人提到了這個問題( https://bugs.chromium.org/p/chromium/issues/detail?id=927066 ),根據回復,這正是官方為了讓 Chrome 更加符合規范行為而做的調整。也就是說,Chrome72 之前的版本,這算是一個沒有按照規范行為而出現的 bug。新的調整,其實就是讓 flex 彈性盒子的子元素最小高度的默認行為應用 min-height:min-content ,就像官方回復中提到的那樣,讓子元素作為 flex 彈性盒子時卻和普通盒子處理方式不同是會讓人困惑的。
解決方法
既然知道了原因,那么如果我們還想使用這樣的布局方式,該怎么做呢?
對的,我們給 item 指定一個最小高度,讓它不使用默認的行為(即內容的高度),一般我們指定最小高度為0 min-height:0。給 item 加上這個樣式后,我們再看一下效果:

嗯,已經符合我們的預期了。為了驗證規范中提到的對主軸方向的行為,我們修改一下代碼,將主軸設置為水平方向試試,代碼如下:
area
item
content
效果如下:

看來主軸為水平方向時,是符合規范預期行為的(Chrome72 及以前的版本都符合),那么我們給 item 加上一句樣式 min-width:0 ,效果如下:

嗯,是符合我們預期的。
結語
好了,現在你已經知道是怎么一回事了,可是等等,你說你升級到Chrome72沒有發現我說的問題?
那是因為官方注意到這個修改會影響到一些網站的正常顯示,因此在 2019 年 2 月 6 日(正是春節假期間)發布的 Chrome72.0.3626.96 中,將這個問題還原回以前的行為了( https://chromium.googlesource.com/chromium/src/+/032ef9666487db1d04b656a095b041de8c6d2b63 )。
官方的意思是為了避免這個修改給某些網站帶來的不好的影響,因此預留時間給大家修改,等到Chrome73將會發布這一改變。所以為了未來更好的瀏覽體驗,檢查一下你的頁面吧!