overflow不一定能隱藏元素(position:absolute)
為了頁面的健壯性,我們常常需要使用overflow:hidden。有時候是為了防止佈局被撐開,有時候是為了配合其它規則實現文字截斷,還有時候純粹是為了建立塊級上下文。
但是,很多人對這個屬性是存在著一定的誤解的,網上很多入門的資料或文章都只提到用overflow:hidden加固定的寬度(或高度)可以強制隱藏內部的超出容器的內容。包括之前我們在使用overflow:hidden建立塊級上下文的方式來實現圖文混排時,都認為overflow:hidden造成了特殊情況下的麻煩(詳見自適應的兩欄圖文混排改進)。但如果認真閱讀一下css規範,會發現overflow:hidden其實並不一定隱藏溢位內容。我之前翻譯的
overflow:hidden並不隱藏所有溢位的子元素
對於overflow:hidden的最大誤解時:當一個具有高度和寬度中至少一項的容器應用了overflow:hidden時,其內部的任何溢位的內容都將被剪裁(隱藏)。 但事實確實如此嗎?答案是“未必”!事實是擁有overflow:hidden樣式的塊元素內部的元素溢位並不總是被隱藏,具體來說,需要同時滿足以下條件:
- 擁有overflow:hidden樣式的塊元素不具有position:relative和position:absolute樣式;
- 內部溢位的元素是通過position:absolute絕對定位;
如果你只關心結論,那麼記住這兩點就夠了。我這裡有個demo,結構如下:
- <divclass="position">
- <h2>position box</h2><divclass="overflow">
- <h3>overflow box</h3>
- <divclass="static">
- <p>This is static child element. This is static child element.
- This is static child element. This is static child element.
- <p>This is static child element. This is static child element.
- This is static child element. This is static child element.<p>
- </div>
- <divclass="absolute">This is absolute child element. This is absolute child element.
- This is absolute child element. This is absolute child element.
- </div>
- </div>
- </div>
程式碼:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf8" />
<title>overflow demo</title>
<style type="text/css">
h2,h3 {margin:0;padding:0.8em 0;}
p {margin:0;pading:5px 10px;}
body {background:#000;color:#fff;}
.position {margin:100px auto;width:300px;background:#000;border:1px solid #fff;position:relative;#zoom:1;}
.overflow {width:100%;background:#f00;overflow:hidden;#zoom:1;}
.static {height:150px;width:450px;background:#00f;}
.absolute {position:absolute;width:350px;height:80px;top:150px;left:-100px;background:#0c0;}
</style>
</head>
<body>
<div class="position">
<h2>position box</h2>
<div class="overflow">
<h3>overflow box</h3>
<div class="static">
<p>This is static child element. This is static child element. This is static child element. This is static child element.<p>
<p>This is static child element. This is static child element. This is static child element. This is static child element.<p>
</div>
<div class="absolute">This is absolute child element. This is absolute child element. This is absolute child element. This is absolute child element.</div>
</div>
</div>
</body>
</html>
在demo中,你可以看到絕對定位的元素被定位到了overflow:hidden的父元素之外,但是它依然被顯示了。而普通元素在水平方向上的溢位被隱藏,垂直方向上撐開父元素。也就是說,普通元素的表現符合我們的預期,而絕對定位元素並不如很多人想當然的那樣被隱藏。
理論依據
那麼,這個原理到底是什麼呢?當然是css2.1規範。在規範中關於overflow的描述中我們可以找到這樣一段話:
This property specifies whether content of a block container element is clipped when it overflows the element’s box. It affects the clipping of all of the element’s content except any descendant elements (and their respective content and descendants) whose containing block is the viewport or an ancestor of the element.
簡單翻譯一下:此屬性(overflow)規定,當一個塊元素容器的內容溢位元素的盒模型邊界時是否對其進行剪裁。它(此屬性)影響被應用元素的所有內容的剪裁。但如果後代元素的包含塊是整個視區(通常指瀏覽器內容可視區域,可以理解為body元素)或者是該容器(定義了overflow的元素)的父級元素時,則不受影響。
即使是我重新整理過的語言,還是感覺有點繞。不過在這段話裡,出現了一個重要的名詞“包含塊”(containing block)。包含塊是什麼呢?這個大家其實比較熟悉,一個絕對定位的元素,其包含塊是最近的擁有relative或者absolute定位屬性的祖先元素,如果任何一級祖先元素都不符合,則其包含塊是body元素。
這就說明,一個絕對定位的元素是否被overflow:hidden隱藏,要看其包含塊相對於overflow:hidden的位置來決定。這就好比駐日美軍,他們不受日本的法律約束而受美國軍法約束。因為他們的“包含塊”是美國軍方而不是日本法院。
A descendant box ispositioned absolutely, partly outside the box. Such boxes are not always clipped by the overflow property on their ancestors; specifically, they are not clipped by the overflow of any ancestor between themselves and their containing block。
翻譯:
一個絕對定位的後代塊元素,部分位於容器之外。這樣的元素是否剪裁併不總是取決於定義了overflow屬性的祖先容器;尤其是不會被位於他們自身和他們的包含塊之間的祖先容器的overflow屬性剪裁。
回到我的demo,overflow的元素位於相對定位的元素與絕對定位元素之間,因此根據規定它不能剪裁絕對定位的子元素。也就是說爺爺相對定位,老爸規定溢位隱藏,可是兒子是絕對定位元素。這時候兒子是否隱藏由爺爺決定,而不是老爸。
應用場景
明白了這個理論,對我們的工作有什麼指導意義呢?
首先,我們知道overflow:hidden並不是萬能的,要想徹底剪裁它的所有子元素,它不但要有overflow:hidden,而且還要作為所有子元素的包含塊(position定位)。這樣萬一某一天你看到overflow:hidden裡面的東東居然被顯示出來了,你才知道是為什麼。
其次,如果我們先定義了overflow:hidden防止容器被撐開,或者用這個方法做了神馬圖文混排、清除浮動之類的處理,甚至是用了overflow:hidden來實現塊級上下文這樣上流的東東,突然產品又說裡面的一個浮層要顯示,要在右邊,要在右上角,要在左邊兩個欄寬外面……那麼你就知道要怎麼搞了。
在oocss中,對模組的定義充分利用了這個特性。oocss的模組基本結構如下:
- <divclass="mod">
- <divclass="inner">
- <divclass="hd"></div>
- <divclass="bd"></div>
- <divclass="ft"></div>
- </div>
- </div>
他們就對inner應用了position:relative,對bd應用了overflow:hidden和_zoom:1。有興趣的童靴可以研究一下