一道面試題目引發的思考

考拉海購前端團隊發表於2017-09-08

起因

多列布局是前端一個經典的反覆被提及的面試題目,最典型的即兩列,左列定寬選單欄,右列變寬為內容區域。

通常得到的答案無外乎左列浮動定寬,然後右列或浮動,或設定外邊距,或絕對定位等等。偶爾會有面試者給出設定右列overflow屬性的答案,心裡就會有些驚喜,繼而會繼續追問,為什麼這麼設定就能實現效果,期待能有進一步驚喜,但基本大部分面試者都止步於這樣設定,並不清楚原因。非常少的面試者會提到這樣設定能夠觸發塊級格式化上下文(Block Formatting Conext, BFC),如果繼續追問觸發BFC的原因,幾乎沒有一個面試者能給出比較滿意的答案。

本文就是由這道面試題目引發的一些思考。針對設定overflow屬性這一方法,做進一步的探討。

overflow屬性

overflow屬性最常見的一個使用場景就是規定當內容溢位元素框時發生的事情。可能的值如下:

  • visible 預設值。元素內容不會被裁剪,元素框之外的內容仍然會呈現。
  • hidden 元素內容會被裁剪,並且元素 框之外的內容是不可見的。
  • scroll 元素內容會被裁剪,但是瀏覽器會顯示滾動條以便檢視其餘的內容。
  • auto 瀏覽器自動處理元素內容的溢位,如果元素內容被裁剪,則瀏覽器會顯示滾動條以便檢視其餘的內容。
  • inherit 規定應該從父元素繼承 overflow 屬性的值。

除此之外,也會經常看到通過overflow屬性實現的一些效果,比如清除浮動,以及上面提到的兩欄佈局的實現。這些效果的實現,可能跟overflow屬性的本意相差甚遠,就像兩種不相關的事務被硬生生的牽扯到了一起。其實不然,CSS Spec規範文件中還明確記錄著overflow屬性的另外一個重要作用。

overflow屬性跟佈局的關係

The CSS2.1 spec mandates that overflow other than visible establish a new "block formatting context".

CSS2.1規範中已經明確提出,設定overflow屬性(非visible)能觸發塊級格式化上下文(Block Formatting Conext, BFC)。

BFC是個很大的話題,此處不展開,這裡給出一個簡化不精確的解釋,BFC概念的引入,一定程度是為了特殊情況下佈局計算的方便,元素觸發BFC之後,其作用就相當於一個根容器,其內部的子元素會跟外界完全隔離開,子元素佈局以及尺寸相關的計算都會以該元素容器為基礎。

為什麼overflow非visible值會觸發BFC?

首先,設定overflow屬性為visible的話,是一種預設情況,就相當於正常預設的佈局,所有超出元素框的內容仍然會正常顯示,不會被裁剪,也不會出現滾動條。但對於其它幾種值的話(hidden, scroll, auto),元素的內容可能會被裁剪,此時,對於某些情況下可能出現的特殊佈局處理就會出現爭議。

比如對於垂直方向緊貼著的兩個元素A和B,其中元素A中浮動的子元素可能會遮住元素B的部分文字區域,此時如果元素B的overflow屬性設定為visible,則內容會包裹在元素A浮動子元素的周圍,這種情況比較容易理解,如下圖。

overflow屬性設定為visible
overflow屬性設定為visible

圖1 overflow屬性設定為visible

但當元素B的overflow屬性設定為非visible的值時,各版本規範的規定就會出現差異。

CSS2.0規範規定,設定非visible屬性值後,元素B的內容仍然包裹浮動元素,如圖2所示。

overflow屬性設定為novisible,CSS2.0規範中的處理
overflow屬性設定為novisible,CSS2.0規範中的處理

圖2 overflow屬性設定為novisible,CSS2.0規範中的處理

此後如果元素B內容發生滾動,每次滾動行為,元素B中發生摺疊的內容(圖3中元素B中文字內容滾動後發生變化)全部要重新計算重繪,實際上這將會帶來很大的效能問題,對滾動體驗也會造成比較大的影響。

overflow屬性設定為novisible,CSS2.0規範中發生滾動時的處理
overflow屬性設定為novisible,CSS2.0規範中發生滾動時的處理

圖3 overflow屬性設定為novisible,CSS2.0規範中發生滾動時的處理

但這裡存在進一步的疑問,即使按此規範的約定,元素B內容滾動時存在效能以及體驗問題,但是非visible屬性中的hidden值,難以理解,元素內容已經被裁剪掉了,為什麼跟其它值auto, scroll歸為一類?這裡面就存在一個誤區,overflow設定為hidden值並不代表內容不可滾動,此時瀏覽器只不過沒有提供可滾動的UI,被"裁剪"掉的內容可以通過JavaScript指令碼來控制滾動,這也是指令碼模擬滾動條的基礎。比如,可以通過JavaScript指令碼設定元素的scrollTop實現圖4的效果,更友好的方式可以自定義一個滾動條。

overflow屬性設定為hidden,CSS2.0規範中發生滾動時的處理
overflow屬性設定為hidden,CSS2.0規範中發生滾動時的處理

圖4 overflow屬性設定為hidden,CSS2.0規範中發生滾動時的處理

事實上各大瀏覽器廠商也都沒有遵照CSS2.0來實現這一部分規範。取而代之,實現的是CSS2.1中的規範內容,即當元素B的overflow屬性設定為非visible值時會觸發BFC,元素B會建立自己的塊級格式化上下文,並會被整體推向右側,如圖5所示。

overflow屬性設定為nonvisible,CSS2.1規範中的處理
overflow屬性設定為nonvisible,CSS2.1規範中的處理

圖5 overflow屬性設定為nonvisible,CSS2.1規範中的處理

備註 上面各圖均來自於參考文獻3

收尾

事實上,一些常見的其它佈局技巧也都是基於上述的原理點,比如overflow屬性非visible值可以用於清除浮動。如果一個面試者,能夠比較清楚地講出上面的各點,相信每個面試官心裡面都會比較驚喜,上面只是自己的一些想法,可能會有些許的鑽牛角尖,但單從這種對細節的鑽研把控程度,候選人就一定不會太差,對候選人來說必然會有很大程度的加分。

上面只是針對兩列布局這道題目一種方案的單方面探討,這種方案有哪些優缺點等等都未提及,如果對每種方案都進行類似程度的擴充,將會發現這其中會涵蓋很多前端知識點,所以看似簡單的題目其實並不簡單。越發覺得前端領域的水很深,夥伴們一起來努力探索實踐吧!

參考文獻

Written by Hong

相關文章