現象
專案中會存在如下幾種巢狀flex結構:
<style>
/* 通用樣式 */
.card {
width: 200px;
height: 300px;
margin: 20px;
border: 1px solid #999;
}
.flex {
display: flex;
flex-direction: column;
}
.header {
flex: none;
height: 40px;
border-bottom: 1px solid #333;
}
.scroll {
overflow-y: auto;
}
.p {
margin: 10px;
height: 400px;
background-color: rgba(0, 0, 0, 0.2);
}
</styl>
<!-- 佈局一 -->
<div class="card flex">
<div class="header">Header</div>
<div class="flex">
<div class="scroll">
<div class="p"></div>
</div>
</div>
</div>
<!-- 佈局二 -->
<div class="card flex">
<div class="flex">
<div class="header">Header</div>
<div class="scroll" style="flex-grow:1;">
<div class="p"></div>
</div>
</div>
</div>
複製程式碼
這在Chrome 73之前的實際展示效果如下(手頭的Electron——Chrome 69):
都是符合期望的結果,scroll是可以滾動的區域,然而,Chrome 73的展示效果卻是: 父元素的高度都被子元素撐開了,導致scroll元素無法滾動。what? why? 納尼?原因
究其原因,規範有關高度的解釋在這一章節,簡單概括就是:
flex元素的最小大小(視主軸方向決定是高還是寬)是內部內容的大小。即,min-height/min-width預設值是“auto”。
emmm...讀“規範”千遍,其義自見。當再三理解這個結論後發覺,似乎,新版Chrome的實現是符合規範的!確實,Chrome的此舉改動就是為了讓瀏覽器的flex佈局行為更貼近規範。
Chrome社群的這個issue:Flexbox rendering changed between chrome 71 and 72,對上面的問題(佈局二),進行了激烈的討論,甚至最終導致了官方的回滾。
至於我們為什麼後知後覺,直到73才大面積暴露該問題,下文花絮會展開解釋。
不過,跟著規範走是完全的政治正確,怎麼說都對!開發者只能順應潮流去改變。
修復
其實,當看到這個現象後,我的內心並沒有經歷太大的波動,因為min-width
曾經已經給我上過預備課了(詳見下文花絮)。所以我很快就找到了解放方式。
找到最外層被撐開的元素,上文兩種佈局裡,都是scroll的直屬父元素,對其增加min-height: 0
的屬性即可修復異常佈局。
如果min-height的行為實在無法理解的話,overflow: hidden
(非visible)也能達到同樣的功效。overflow平時用的比較多,相對會更有體感,如下例:
<div style="height: 200px;overflow: scroll;">
<div style="height: 400px"></div>
</div>
複製程式碼
當父元素設定了overflow:hidden/scroll,展示時,父元素就會隱藏子元素的溢位部分。
當然,flex佈局中的overflow,它的實際作用也就是把min-height
設定為0。
此外,還可以對子元素,上文示例中即scroll元素,設定height: 100%
來修復。但當層級比較多時,需要將該屬性一層層往下傳遞,不夠環保。
花絮
問題是順利修復了,下面是一些插曲~
1. Chrome 71->72->73
這個改動首發於Chrome 72,但為什麼直到Chrome 73才被我們注意到?因為Chrome 72釋出後,由於反響強烈,Chrome決定先回滾改動,給開發者更多的時間來適應該改動。
然而Chrome 72的釋出,以及72的後續回滾釋出都發生在中國春節假期期間,沒什麼使用者反饋,對於中國開發者,例如我,完全沒注意到這次預警。。。
2. min-width的學前教育
為什麼說我已經被min-width提前教育過?
我實現過類似編輯器的tab:
這裡就是巢狀的flex橫向佈局,在預設樣式下,滾動區會被子元素撐開,也就是此時,我第一次領略了當初就覺得很奇怪的min-width: 0
的寫法。
那為什麼那時就需要顯式宣告父元素的min-width
呢?此外,這次升級所造成的誤傷都是發生在縱向佈局的flex上,那橫向佈局的flex有影響嗎?
答案其實很狗血,因為Chrome對於min-width
的預設值,從很早期就設定為符合規範的“auto”了。。。