CSS2.1SPEC:視覺格式化模型之包含塊,
原汁原味的才是最有味道的,在閱讀CSS標準時對這一點的體會更加深刻了,閱讀文檔後的一大感覺就是很多看上去理所應當的樣式表現也都有了對應的支援機制。本文首先從包含塊寫起,一方面總結標準中相應的闡述,並且結合具體的執行個體進行具體分析,特別是對於CSS2.1支援並不完善的IE6/7。由於經驗尚淺,文中肯定存在一些問題,希望大家可以多多包涵並且指出問題。 閱讀本文前,應當對於CSS盒模型以及視覺格式化模型中會產生的各種框(box,也可以成為盒子)以及各種不同的布局方式有比較準確的認識,可以閱讀杜瑤大神的兩篇文章,這兩篇文章也是對標準中相關章節的翻譯和闡述。(1)視覺格式化模型中的各種框(2)置換和非置換元素 或直接閱讀CSS2.1 SPEC中的相關章節:(1)Box model(2)Visual formatting model 在講包含塊之前還是想先簡單說一下視覺格式化模型 1、CSS視覺格式化模型標準中對於視覺格式化模型的闡述為:how user agents process the document tree for visual media.即使用者代理程式在視覺媒體下如何處理文檔樹,使用者代理程式最常見的比如瀏覽器,而負責頁面解析和渲染的就是瀏覽器的渲染引擎(現在更多地直接稱為瀏覽器核心),文檔既可以包括HTML文檔,也包括其他通用標記語言所編寫的文檔。在視覺格式化模型中,文檔樹中的每個元素都會根據盒模型產生0個或多個框,影響這個框的布局的因素有: (1)框的尺寸和類型,比如塊級框和行內級框的布局方式就是不同的。 (2)框的定位方式,display屬性絕對了一個元素所產生的框的定位方式,定位方式不同的框在布局時也有不同的規則。 (3)與其他框的關係,假如有兩個框,它們之間是內含項目關聯性還是同輩關係而所產生的布局是不相同的。 (4)其他的額外資訊(比如視口的大小,置換元素的固有尺寸等)從這個角度講,視覺格式化模型就是對上述這些因素是如何影響一個框的布局而進行的詳細描述。 2、視口(viewport)第一部分中出現了視口這個詞,直觀上看,我覺得視口可以理解為使用者代理程式用來呈現解析和渲染後的文檔樹的地區,使用者通過這個地區可以閱讀文檔得內容,在瀏覽器中,視口一般就是瀏覽器用於呈現網頁的地區。標準中對於視口的闡述為:
User agents for continuous media generally offer users a viewport (a window or other viewing area on the screen) through which users consult a document.
注意加粗的continuous media,我們平時所瀏覽的網頁就屬於連續媒體,而通過印表機列印的文檔內容必須是分頁的,所以就是分頁媒體,即paged media(此處的解釋略粗糙,僅是個人的簡單看法)。網頁是連續的媒體,那麼問題就來了,視口不可能跟隨網頁的大小而變化,因此視口在小於文檔的尺寸時,必須提供一種滾動機制,最常見的就是瀏覽器的捲軸,通過捲軸我們就可以瀏覽超出視口的文檔部分,也就是文檔中闡述的:
When the viewport is smaller than the area of the canvas on which the document is rendered, the user agent should offer a scrolling mechanism.
當然關於視口的知識點可不只是上述的這麼簡單,比如在移動web中,viewport的相關屬性對於移動web的開發至關重要,但本文暫不涉及其他關於視口的知識點。
3、包含塊(containing block)一個網頁是由一個一個的框(box)所組成的,每一個框在頁面中都有自己的尺寸、位置以及其他的渲染屬性(如背景色,字型等),那麼這些框在布局的時候,它們的位置是如何決定的呢?另外,如果沒有為框定義顯示的尺寸(width,padding,border,margin)等,那麼它們的尺寸又是如何確定的呢?答案的關鍵點就是包含塊,個人認為,包含塊是學習CSS布局時基礎中的基礎,不過還好,這個概念也並不難理解。首先看一下標準中對於包含塊的闡述:The position and size of an element's box(es) are sometimes calculated relative to a certain rectangle, called the containing block of the element.即視覺格式化模型中所產生的各種框,它們的位置和大小往往都是根據一個特定的矩形框邊緣來計算得到的, 這個矩形框就是這個box的包含塊。註:如果講一個框的包含塊時,指的是它所處的包含塊,而不是它形成的包含塊。 那麼該如何確定一個框的包含塊呢?標準中規定了相應的規則:
3.1根項目的包含塊 根項目(HTML中就是html標籤)的包含塊稱為初始包含塊:對於連續媒體(比如網頁),它具有視口的尺寸並且定位在畫布的原點(可以直觀理解為視口的內容起始位置,如果初始包含塊的direction屬性為ltr,那麼起點位置就是視口的左上方,如果為rtl,那麼就為視口的右上方)。初始包含塊的direction與根項目的direction屬性相同,預設為ltr,即從左至右。 特別注意:初始包含塊具有視口的尺寸,也就是說寬高都是和視口相同的,即使視口中出現了滾動
3.2元素定位為static(預設值)或relative(相對布局)時的包含塊
對於定位屬性為static(預設值)或relative(相對布局)的元素,其包含塊是由最近的祖先塊容器框的內容地區構成。這一點也比較好理解,雖然出現了塊容器框和內容地區兩個詞,對於CSS盒模型和視覺格式化模型中的各種框有所瞭解後應該就能明白。下面有個簡單的例子:##DEMO 1:static或relative定位的元素的包含塊CSS代碼:
.container{
width: 1000px;
margin: 50px auto;
border: 2px solid #000000;
padding: 50px;
}
HTML代碼:
<div class="container" style="">
<div class="static-div-1" style="background: #CCCCCC;">
static定位的元素
</div>
</div>
帶黑色邊框的container有50px的padding,可以看到class為static-div-1元素是基於container的內容地區(content area)來定位的,這一點IE6/7也都是遵循標準的。
3.3元素定位為absolute時的包含塊
對於position為absolute的元素,其包含塊為最近的擁有非static定位屬性(即position為relative,absolute或fixed)的元素所產生,有下面兩種情況: <1>如果這個元素為一個塊容器框元素,那麼包含塊由這個元素的內邊距邊界(padding edge)形成 <2>如果這個元素是一個行內元素,那麼這個包含塊由包圍該行內級元素的第一個行框和最後一個行框的box形成。如果行內元素被分割成了多行,那麼在CSS2.1中,包含塊則是未定義的。 如果沒有這樣的祖先,那麼其包含塊就是初始包含塊註:在分頁媒體中包含不一樣的情況,本文暫不討論分頁媒體中的情況 absolute的情況相對複雜一些,看以下例子:
##DEMO 2:絕對位置元素的包含塊(1)-塊容器框形成包含塊CSS代碼:
.container{
width: 1000px;
margin: 50px auto;
border: 2px solid #000000;
padding: 50px;
position: relative;
}
.absolute-div-1{
position: absolute;
left: 0px;
top: 0px;
}HTML代碼:
<div class="container">
<div class="absolute-div-1">
absolute定位的元素
</div>
</div>
效果如下:
可以看到,absolute-div-1的元素是絕對位置,並且定位起點為左側0px,上部0px,雖然container有50px的padding,但由於絕對位置的元素是根據塊容器框的padding edge來定位,所以absolute-div-1還是緊貼左上方顯示。
##DEMO 3:絕對位置元素的包含塊(2)-行內元素形成包含塊DEMO3中,我們把container換成行內元素span,為了更明顯地顯示效果,我們給body加了一個高度並且設定了背景色,並且為span和absolute-div-1設定了不同的字型顏色,代碼如下CSS代碼:
body{
margin: 0px;
font-size: 14px;
height: 500px;
background: #a0b3d6;
}
.container{
margin: 50px auto;
position: relative;
color: #eeeeee;
}
.absolute-div-1{
position: absolute;
color: #ff0000;
left: 0px;
top: 0px;
}HTML代碼:
<span class="container">
行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊
行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含
行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含
行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含
<div class="absolute-div-1">
absolute定位的元素
</div>
</span>
效果:在IE6/7中效果也相同,另外我們提到過,如果元素是一個行內級元素,那麼這個包含塊由包圍該行內級元素的第一個行框和最後一個行框的box形成。我們來驗證標紅部分的闡述,即把absolute-div-1的top定位改為bottom,即bottom:0px,效果如下:這也驗證了標準中所闡述的內容。 註:在IE6中,絕對位置元素如果只用bottom定位,但是形成包含塊的元素沒有觸發hasLayout時,bottom不會根據包含塊的底部來定位,這個bug通過zoom:1等屬性觸發hasLayout可以解決。
##DEMO 4:絕對位置元素的包含塊(4)-行內元素被分割成多行時
視覺格式化模型中描述過,如果一個行內級元素包含了區塊層級元素,那麼這個行內級元素就會被分割成2塊,並且都成為了區塊層級元素。我們把DEMO3中的container改動一下:<
span
class=
"container">
行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊
行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含
<div style="background: #eeeeee">中間出來了一個div</div>
<div class="absolute-div-1">
absolute定位的元素
</div>
行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含
行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含
</span>
此時的效果在不同的瀏覽器中存在差異:IE6+和firefox中的效果為:而chrome中的效果為:可以看出,chrome中的絕對位置元素在定位時是基於被分割後形成的第二個框來定位的,而如果我們把絕對位置元素移動到分割元素之前,即:
<span class="container">
行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊
行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含
<div class="absolute-div-1">
absolute定位的元素
</div>
<div style="background: #eeeeee">中間出來了一個div</div>
行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含
行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含塊行內級包含
</span>
那麼chrome中的效果就成了:
可見,chrome中的位置是與絕對位置元素在代碼中的位置相關的。
##DEMO 5:絕對位置元素的包含塊(4)-初始包含塊作為包含塊如果一個絕對位置元素找到有非static定位屬性的祖先,那麼初始包含塊就作為其包含塊,這裡需要注意的是初始化包含塊的尺寸問題,2.1節中曾經講過初始包含塊具有視口的尺寸,即使存在滾動時,DEMO代碼如下:CSS代碼:為了出現滾動,我們為body加了1000px的高度
.body-for-demo4{
height:1000px;
background: #a0b3d6;
}
.absolute-div-2{
height: 100px;
width: 100px;
background: #03a9f4;
position: absolute;
bottom: 0px;
left:0px;
}
HTML代碼:
<body class="body-for-demo4">
<div class="absolute-div-2">
</div>
</body>
效果如下:
可以看到,雖然body的高度超出了初始包含塊使得捲軸出現,但是初始包含塊的尺寸時沒有發生改變的。如果我們把body設定一個position:relative的屬性,那麼絕對位置框就會跑到頁面底部了。
2.4元素定位為fixed時的包含塊
元素定位屬性為fixed時,對於連續媒體,包含塊由視口形成,對於分頁媒體,則由頁面地區形成。position為fixed的元素特點是不隨頁面的滾動而滾動,它的包含塊由視口形成,這一點也比較好理解。但是IE6不支援fixed的屬性,可以使用css運算式或者hack的方式使IE6支援fixed。可參考:http://caibaojian.com/468.html
另外CSS2.1標準的原文第10章第1節中也有包含塊的樣本,標準中的樣本更加基礎,同樣也可以參考。