[CSS] overflow 同時設置 visible 與其他屬性衝突問題

Sean Chou
Recording everything
7 min readOct 20, 2019

--

前一陣子在開發過程中,遇到了一個有關 CSS 有趣的問題,趁記憶模糊之前在這裡把它記錄下來。

#問題

需求是這樣,畫面左側有個可以滾動的側邊欄,中間會有一個可能內容會超出側邊欄的 dropdown menu,主頁面上除了可以滾動,又還有一個固定的 header,大概就如下面的示意圖所示。

當看到這個需求的時候,其實很直覺就會想到把側邊欄的 div 設置 Y 軸可以滾動,X 讓他可以超出範圍,好像很簡單就解決了(?)

.sidebar {
overflow-y: auto;
overflow-x: visible;
}

結果長出來的竟然是這樣

看到這個,第一個想法就是去調 z-index (補洞),但怎麼調都是沒有效果。後來 survey 了一些文件跟討論串才找到最根本的原因。

# 原因

在 W3C 的文件中,關於 CSS overflow 的 visible 屬性有一段定義:

visible’

There is no special handling of overflow, that is, the box’s content is rendered outside the box if positioned there. The box is not a scroll container.

https://www.w3.org/TR/css-overflow-3/#valdef-overflow-visible

簡單說,visible 是為了讓你的 box content 超出這個 box 的時候所使用的,但是這個 box 不可以是 scroll container

在 StackOverflow 中也有在討論這個問題

If you are using visible for either overflow-x or overflow-y and something other than visible for the other, the visible value is interpreted as auto.

https://stackoverflow.com/questions/6421966/css-overflow-x-visible-and-overflow-y-hidden-causing-scrollbar-issue

也有人引用這段 (出處連結我找不到了,應該是 W3C)

The computed values of ‘overflow-x’ and ‘overflow-y’ are the same as their specified values, except that some combinations with ‘visible’ are not possible: if one is specified as ‘visible’ and the other is ‘scroll’ or ‘auto’, then ‘visible’ is set to ‘auto’. The computed value of ‘overflow’ is equal to the computed value of ‘overflow-x’ if ‘overflow-y’ is the same; otherwise it is the pair of computed values of ‘overflow-x’ and ‘overflow-y’.

所以結論就是,想要同時在一個 box 上做到可以滾動,內容又可以超出這個 box?

# 解決方法

解決方法其實很多種,但也跟你的需求設計有著很大的關係,並不是所有解決方法都適用。

把滾動的範圍跟要超出 box 的元件分開

如果拿剛剛那個例子來說,只讓下面的 content 那塊可以滾動,上面的內容設定可以超出 box,兩塊不要放在同一個 div 裡面就解決了

HTML

<div class="sidebar">
<div class="sidebar-content-select"></div>
<div class="sidebar-content-scroll"></div>
</div>

CSS

.sidebar-content-select {    
overflow-x: visible;
}
.sidebar-content-scroll {
overflow-y: auto;
}

BUT!!!!

這樣就跟 UX 的設計有關了,改成這樣後能滾動的範圍就只剩下下面那塊了,如果本來 Designer 的設計,因為想要下面內容可以更完整顯示,要整塊Sidebar 都可以滾動呢?

一種解法就是去找 Designer (?)

在必需要妥協設計的情況下,我們還有沒有其他解法呢?

動態改變 CSS Class Name

那是不是打開 dropdown 的時候就不要讓它滾動就好啦?

確實,這是一個解法。只要在收到 dropdown onOpen 的 event 時候,我們去動態置換掉 sidebar 的 class name ,打開的時候 overflow-x: visible; ,關起來的時候變回 auto 就解掉這個問題了。

但是實務上也是會有些問題的,第一個是切換到不能 scroll 的狀態時,div 會滾回最上端,如果 user 滑到一半心血來潮打開了 dropdown,但這時候 sidebar 會瞬間滑回最上方。

第二個問題是當螢幕過小的時候,如果 dropdown 的階層或是深度比較深,打開的同時當下螢幕沒辦法完全顯示,但這時候又無法利用 scroll bar 來往上拉。

User 可能會?

把 Dropdown 拿出來位置用算的

還有一個自己覺得並不是很好,而且 effort 也不小的方法提供參考,就是只把 dropdown 那塊獨立出來,他的垂直位置就用計算去改變。

這樣是可以解決這個問題沒錯,但是需要 handle 的部分就變多了很多很多。你要去處理 dropdown 初始長出來的位置(這個倒還容易解決),Scroll 當下 dropdown 應該要移動到哪裡,難保不會有一些 performance issue 出現。而且這樣做下去之後,本來簡單的需求突然多了很多很多所謂的 workaround 方法,對於後續 maintain 上也不是一個很好的方向。

針對這個 Case 的其他 issue

在剛剛這個 Case 其實也會發現,設計上也是有問題的。

當開啟 dropdown 的當下,左側的 scroll bar 如果滾到太上面,超過右側 fix header 的時候,會面臨一個不知道誰該在上面的尷尬情況。

當然這些問題都跟 UX 上的設計有關,在這個領域我也不是專業,這裡就不來討論這個問題。

# 小結

關於這個小小的 issue,其實有很多很多面向可以下去討論,每個人遇到的 Case 可能也不盡相同,要去尋找最於自己專案最適合的方式來解決。

P.S. 其實 CSS 這塊我也不太熟,如果內容有不正確的,歡迎一起討論討論

如果你覺得這篇文章對你有幫助,歡迎買杯咖啡贊助 ☕️ 謝謝

--

--