在本文中將使用四種常見的做法,結合CSS於結構化標記語法制作兩欄布局.很快地就會發現,不用嵌套表格,間隔用的GIF也能做出分欄版面布局.
相關文章:CSS網頁布局開發小技巧24則
稍後在"技巧延伸"中,將會討論Windows版Internet Explorer 5.0盒模型的問題,以及繞過它的方法.也將分享一個以CSS達成等寬欄位的簡單秘密.
要如何以CSS作出兩欄版面布局?
答案是有好幾種方法,為了帶領你起步,同時幫助你了解兩種常見方法的差異(浮動與定位),因此先把焦點放在四種不同的方法上,在此每一種方法都能做出兩欄布局,同時具備頁首和頁尾.
我的願望是:你能以本章作為指引開始構建一個網站,並發揮本書其他章節之內的方法制作內容.
我們將討論的四種方法都應用在文檔的<body>與</body>標簽之間,同時我會在開始討論每種方法之前介紹將會使用的標記語法結構.
為了讓你了解圍繞著每種方法的頁面結構,讓我們大致看一下還需要加入些什麼:
<!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" lang="en" xml:lang="en">
<head>
<title>CSS Layouts</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
...方法示范...
</body>
</html>
為了讓你可以了解要達成的版面配置,請看圖12-1:這就是我們想要完成的分欄版面布局.
圖12-1 兩欄布局的框線圖
方法A:浮動側邊欄
<div id="header">
...頁頭部分...
</div>
<div id="sidebar">
...側邊欄部分...
</div>
<div id="content">
...主體部分...
</div>
<div id="footer">
...頁腳部分...
</div>
上面就是我們要以CSS的float屬性制作成分欄布局的標記源代碼,使用<div>標簽把頁面元素分成幾個邏輯段落,每個都設定了唯一的id:
把這些頁面段落拆開,能讓我們能完全控制版面布局,只要指定幾條CSS規則,就可以馬上完成兩欄布局.
為頁首與頁尾指定樣式
要把內容結構轉化成分欄布局的第一步,是為頁首,頁尾加上一點背景顏色以及一點內補丁,這樣能使內容更容易凸顯出來.
#header {
padding: 20px;
background: #ccc;
}
#footer {
padding: 20px;
background: #eee;
}
為方法A的結構加上前面這段CSS會使它顯示成圖12-2這樣,我為各個段落加了一些假象的內容.
圖12-2 為頁首,頁尾指定樣式
當然,在#header與#footer裡,可以繼續為這些段落指定適當的樣式,像是font-family,color,鏈接色彩等等.現在讓我們把兩欄版面制造出來.
浮動側邊欄
方法A的精華,在於它以float屬性把#sidebar放到主要內容<div>的任一邊去.以這個例子來說,將它放到內容的右側,但是放到另一側當然也行.
浮動#sidebar的關鍵在於,在標記源代碼中,必須出現在主內容<div>之前,這樣一來,側邊欄的頂部就會與主內容的頂部排齊.
接著,為#sidebar加上float屬性,同時把它的寬度設為30%,指定背景顏色:
#header {
padding: 20px;
background: #ccc;
}
#sidebar {
float: right;
width: 30%;
background: #999;
}
#footer {
padding: 20px;
background: #eee;
}
圖12-3是加上這段CSS之後的顯示效果,能看到側邊欄跑到右邊去了,而主要內容在側邊欄范圍之內流動.
圖12-3 把#sidebar浮動到主要內容的右側
真正的欄位
看看圖12-3,我們還沒有真正完成兩欄布局,為了完成這個效果還必須取#content這個<div>,指定與憂側邊欄寬度相同的右外補丁,因此產生放置#sidebar的空間.
需要加上的CSS就是這麼簡單:
#header {
padding: 20px;
background: #ccc;
}
#sidebar {
float: right;
width: 30%;
background: #999;
}
#content {
margin-right: 34%;
}
#footer {
clear: right;
padding: 20px;
background: #eee;
}
我們會發現,我們給content設定的右外補丁大小比#sidebar還大4%,如此能在兩欄之間留下一點空位.圖12-4是以浏覽器查看的效果,你可以發現只要為<div>設定右外補丁,就能造出第二欄的假象.
圖12-4 兩欄布局
同時要留意的是對#footer所加上的clear:right規則,這個規則很重要,能確保頁尾一定會出現在側邊欄和內容區之後,而不受兩欄的長度變動影響,頁尾會避開任何先前出現的float內容.
現在有了能使用的兩欄布局,可以繼續為現在的CSS聲明加上更多邊界,背景,邊框與其他元素,使外觀更吸引人.
至今為止我們都以百分比設定寬度,以便造出靈活的布局(欄寬會自動隨著使用者的視窗寬度縮放).我們也能以像素單位造出定寬布局,但是以像素指定內外補丁大小時,必須注意IE for Windows錯誤解析CSS盒模型的問題,你能在本章的"盒模型問題"找到更多信息以及能用的解決方法.
方法B:雙重浮動
<div id="header">
...header content here...
</div>
<div id="content">
...main content here...
</div>
<div id="sidebar">
...sidebar content here...
</div>
<div id="footer">
...footer content here...
</div>
方法A的缺點之一是:為了浮動側邊欄,則必須在標記源代碼之內把側邊欄放到主內容<div>的前面,關閉CSS的浏覽器,文字浏覽器,屏幕閱讀器與其他不支持CSS的設備將會在頁面主要內容之前顯示(或念出)側邊欄的內容.這樣實在不嚴謹.
我們可以利用float做法,並避開這個問題,只要交換標記源代碼裡的主內容,側邊欄<div>的位置(如上所示),然後以CSS將兩者浮動到不同邊即可.
#header {
padding: 20px;
background: #ccc;
}
#content {
float: left;
width: 66%;
}
#sidebar {
float: right;
width: 30%;
background: #999;
}
#footer {
clear: both;
padding: 20px;
background: #eee;
}
通過把兩個<div>浮動到不同方向,就能以最恰當的方式排列源代碼(主內容放在側邊欄前面),同時仍能得到圖12-4這樣的效果.
避開兩邊
同樣重要的是,你必須將#footerdeclear屬性設為both,如此一來不管兩欄的長度多長,頁尾總是顯示在最後,而標簽源代碼的內容順序也改善了.
方法C:浮動主內容
<div id="header">
...頁頭內容...
</div>
<div id="content">
...主內容...
</div>
<div id="sidebar">
...側邊欄...
</div>
<div id="footer">
...頁尾內容...
</div>
還有個值得一提的方法,只需要用一個float屬性,同時標記源代碼仍然可以將主內容的<div>放在側邊欄之前.
只要將主內容的<div>浮動到左側,並且為它設定小於100%的寬度,如此一來就能在右側留下足夠空間擺放側邊欄.
CSS內容
方法C需要的CSS內容再簡單不過了,"一個float屬性",內容區希望使用的寬度,以及兩欄之間留下的小邊界.
#header {
padding: 20px;
background: #ccc;
}
#content {
float: left;
width: 66%;
}
#sidebar {
background: #999;
}
#footer {
clear: left;
padding: 20px;
background: #eee;
}
請注意我們並不需要定義側邊欄的寬度,因為它會自動填滿主內容<div>用剩下的空間(在這個例子中是34%).
悲慘的背景
圖12-5就是以浏覽器查看的成果,哦喔!在某些常用浏覽器裡,側邊欄的背景顏色會出現在主內容區底下,由於側邊欄並未制定寬度,因此它想擴到與浏覽器視窗一樣寬.
圖12-5 浮動內容,但是側邊欄的背景顏色透了出來
這個部分只要我們能在側邊欄左邊加上寬度與內容區相同的外邊界便可以避開這個問題.實際上我們會把外補丁設的稍微大一點,以便在兩欄之間留下一點空白.
#header {
padding: 20px;
background: #ccc;
}
#content {
float: left;
width: 66%;
}
#sidebar {
margin-left: 70%;
background: #999;
}
#footer {
clear: left;
padding: 20px;
background: #eee;
}
簡單樸素
或者是,如果涉及不需要用到背景色的話,那就不必設定邊界了,圖12-6是去掉整個#sidebar聲明,在為主內容<div>加上一點右外補丁之後的結果.此時兩欄會共用頁面預設的背景色.
圖12-6 不使用背景色的浮動內容
CSS則能縮減成:
#header {
padding: 20px;
background: #ccc;
}
#content {
float: left;
width: 66%;
margin-right: 6%;
}
#footer {
clear: left;
padding: 20px;
background: #eee;
}
除了加上左外補丁(或是省去背景色)之外,還有個使用背景圖片的替代做法能讓分欄具備背景色彩,我稍後會在本章的" 技巧延伸 "單元裡提示這個小秘密.
方法D:定位
<div id="header">
...頁首內容...
</div>
<div id="content">
...主內容...
</div>
<div id="sidebar">
...側邊欄...
</div>
<div id="footer">
...頁腳內容...
</div>
方法D是使用相同的標記源代碼結構,然後以最有效率的方式排列<div>:把主內容放在側邊欄之前,關閉樣式的浏覽器,屏幕閱讀器會先收到主內容部分,再收到側邊欄,在定位時,標記源代碼內的順序與頁面元素出現的位置沒有關系.
能夠預測的高度
CSS內容與前三個方法有點類似,第一個差異是對頁首指定的像素高度,我們需要能夠預測的高度以便稍後為側邊欄定位.
在這裡隨機選了一個數字,而這需要根據頁首使用的內容調整,像是標志,導航欄,搜索表單等.
#header {
height: 40px;
background: #ccc;
}
#footer {
padding: 20px;
background: #eee;
}
為各欄留下空間
接著,要為#content這個<div>設定右外補丁,就像前幾個方法一樣,這能為右側邊欄留下空間,稍後會使用絕對定位法(不是浮動)把右側邊欄放進去.
#header {
height: 40px;
background: #ccc;
}
#content {
margin-right: 34%;
}
#footer {
padding: 20px;
background: #eee;
}
放進側邊欄
最後,要使用絕對定位法把#sidebar這個<div>放到#content的邊界裡,也必須去掉浏覽器在頁面周圍加上的預設邊界,如此一來定位座標在所有浏覽器之內就會一致了.
body {
margin: 0;
padding: 0;
}
#header {
height: 40px;
background: #ccc;
}
#content {
margin-right: 34%;
}
#sidebar {
position: absolute;
top: 40px;
right: 0;
width: 30%;
background: #999;
}
#footer {
padding: 20px;
background: #eee;
}
在指定position:absolute之後,就能以top與right坐標把#sidebar准確的放到所想的位置(圖12-7).
圖12-7 以定位做出的兩欄布局效果
我們敘述了 "把 #sidebar這個<div>放到距離浏覽器視窗上邊緣40像素,右邊緣0像素的位置",除此之外,也能用bottom和left指定坐標.
頁尾問題
以先前的方法浮動分欄時,可以用clear屬性確保頁尾橫跨整個浏覽器視窗的寬度,而不受主內容,側邊欄的長度影響.
在定位時,側邊欄的文檔流獨立於整個頁面之外,所以只要側邊欄比內容還長,它就會蓋住頁尾部分.(圖12-8)
圖12-8 側邊欄與頁尾重疊
面對這個問題我常用的解決方法之一,是為頁尾指定與主內容一樣的右外補丁,讓側邊欄能夠延伸超過頁尾.
使用這個方法的話,CSS需要調整成這樣:
body {
margin: 0;
padding: 0;
}
#header {
height: 40px;
background: #ccc;
}
#content {
margin-right: 34%;
}
#sidebar {
position: absolute;
top: 40px;
right: 0;
width: 30%;
background: #999;
}
#footer {
margin-right: 34%;
padding: 20px;
background: #eee;
}
這個解決方案在內容很短,側邊欄很長的頁面上看起來有點怪,但是它的確有效,結果可參照圖12-9,示范了側邊欄避開頁尾的情況.
圖12-9 外補丁和主內容相同的頁尾
除了使用float屬性之外,也能用定位制造出分欄布局,讓我們看看最後一個選擇,方法D.
三人行
如果想做三欄布局的話該怎麼辦?沒問題,而且在使用絕對定位時很容易加入.只需要為主內容,也為加上左外補丁,大小足夠容納第三欄即可.
另一個側邊欄能夠放在標記源代碼之內任何地方,因為會需要再度使用絕對定位進行布局.
假設加了第二個側欄,並將它取名# sidecolumn,接著以下面這段CSS為它空出位置,再把它放進去.
body {
margin: 0;
padding: 0;
}
#header {
height: 40px;
background: #ccc;
}
#content {
margin-right: 24%;
margin-left: 24%;
}
#sidecolumn {
position: absolute;
top: 40px;
left: 0;
width: 20%;
background: #999;
}
#sidebar {
position: absolute;
top: 40px;
right: 0;
width: 20%;
background: #999;
}
#footer {
margin-right: 24%;
margin-left: 24%;
padding: 20px;
background: #eee;
}
剛才完成的部分是在主內容,頁尾區空出左外補丁(避免重疊),與之前做右側邊欄一樣,接著以絕對定位法放進新的#sidecolumn ,將它放在距離上邊緣40像素,距離左邊緣0像素的位置.
你有留意我們稍微修正了寬度以容納第三欄嗎?由於我們使用百分比,因此這個布局會隨著浏覽器的寬度縮放,或者也可以為任何一欄指定像素寬度,以便使布局寬度固定下來.
圖12-10是用浏覽器查看這個示例的效果,一份以CSS絕對定位完成的靈活三欄布局.
圖12-10 以定位法作出的靈活三欄布局
歸納
我們在這章稍微研究了以CSS規劃版面布局是能夠達成的效果.本章的目的是提供你發揮的基礎,因此示范了兩種主要的做法: 浮動和定位.
我希望你能繼續深入嘗試CSS布局技巧,去掉頁面內的嵌套表格,並且換上更多浏覽器與設備能讀取的靈活的結構化的標記語法.
如果你想知道更多關於CSS版面布局的資訊,那麼一定要看看這些資源:
技巧延伸
現在我們經過了建立基本CSS布局的基礎,該是討論Windows版Internet Explorer 5與5.5版,以及它們錯誤解析CSS盒模型這個不幸問題的時候了.稍後也會分享一個通過平鋪背景圖片達成等高欄位布局的秘密技巧.
盒模型問題
本章開始的時候我們討論了建立多欄CSS布局的方法,只用width屬性定義每欄的寬度,當你開始為這些欄位加上補丁,邊框的時候,事情就變得有些復雜了.為什麼?
不幸的是,Internet Explorer 5 for Windows在加上內外補丁,邊框的時候,無法正確計算外包元素的寬度.
舉例來說,除了IE5 for Windows之外,所有支持CSS1的浏覽器都會將外包元素的寬度計算為寬度,內補丁,邊框三者相加,這是W3C希望所有浏覽器處理CSS盒模型的方式.
但是IE5 for Windows會將邊框和內補丁算在指定的寬度之內,搞混淆了?不用擔心,直接看看問題會對你有所幫助.
眼見為實
比較一下圖12-11和12-12,圖12-11是個200像素寬的元素,兩側各有10像素的內補丁,以及5像素的邊框,把水平部分的數值全加起來,就能知道實際寬度為230像素.
圖12-11 盒模型的正確計算結果
圖12-12 IE5 for Windows 錯誤的內補丁,邊框,寬度計算結果
這是符合設計的盒模型:width屬性總是定義元素的內容范圍,而內補丁,邊框則會加到這個數值上.
因此,如果將側邊欄的寬度定義成200像素然後加上內補丁和邊框,CSS的聲明如下:
#sidebar {
width: 200px;
padding: 10px;
border: 5px solid black;
}
把寬度設定為200像素,但是側邊欄實際需要230像素的空間,除了IE5 for Windows以外. IE5 for Windows 裡側邊欄總共會占用200像素,把內補丁和邊框都算在裡面.
圖12-12 顯示的是當width屬性指定為200像素時,邊框和內補丁會占用內容空間,而不是內容空間之外.
搖擺不定的寬度
我們反對為元素指定邊框,內補丁的理由就是實際寬度會隨著使用者浏覽器的不同而不同,就算在今天,幾百萬使用IE5.x的用戶還是會看到明顯偏差的設計結果.同時有個重點必須記住:在這段文字撰寫的時候,仍然有太多人在使用IE5以致我們不能忽視這個問題.
所以該怎麼辦?恩,幸運的是,有個能修復這個問題的技巧,這個技巧可以提供兩種不同的寬度,一種給IE5 for Windows,另一種給其他浏覽器以便得到正確的盒模型.
盒模型Hack
親切的Tantek Celik寫了盒模型Hack (http://www.tantek.com/CSS/Examples/boxmodelhack.html) 讓我們能提供兩種不同寬度:一種調整過,只會被Window Internet Explorer 5使用,另一種則給其他所有浏覽器使用.
通過IE5和IE5.5才有的CSS解析Bugs,可以指定一個略大的寬度(容納邊框和內補丁),然後以實際的寬度覆蓋這個數值,讓其他浏覽器能顯示出正確的結果.
源代碼示例
舉例來說,如果希望把側邊欄的內容區域寬度設為200像素寬,加上10像素內補丁和5像素邊框,那麼我們的CSS看起來就像:
#sidebar {
width: 200px;
padding: 10px;
border: 5px solid black;
}
對IE5 for Windows來說,則需要把寬度指定為230像素(加上兩側內補丁和邊框的寬度),接著再以200像素覆蓋回來,讓符合標准的浏覽器得到正確的寬度.
#sidebar {
padding: 10px;
border: 5px solid black;
width: 230px; /* for IE5/Win */
voice-family: "\"}\"";
voice-family: inherit;
width: 200px; /* actual value */
}
留意IE5 for Windows的值先出現,接著幾條讓IE5 for Windows認為聲明已經結束的規則,在此我們使用voice-family屬性,原因單純只是浏覽器認得它的話也不會改變視覺效果,最後指定實際的寬度,覆蓋最初的width規則,第二個width規則會被IE5 for Windows忽略.
結果在IE5 for Windows以及其他所有兼容CSS2的浏覽器上看起來應該完全相同.沒有使用這個hack的話,IE5 for Windows的使用者就會看到比設計還瘦的欄寬.
對Opera友好
對於同樣擁有IE5 for Windows解析錯誤的CSS2兼容浏覽器來說,我們必須在每次使用盒模型補丁之後加上一段額外的聲明,這個稱為"對Opera友好"的規則會讓所有符合標准的浏覽器不被解析Bug卡住,確保他們能顯示出期望中的寬度.
#sidebar {
padding: 10px;
border: 5px solid black;
width: 230px; /* for IE5/Win */
voice-family: "\"}\"";
voice-family: inherit;
width: 200px; /* actual value */
}
html>body #sidebar {
width: 200px;
}
有了這段規則,就可以完全繞過IE5 for Windows錯誤解析CSS盒模型的問題,讓所有人都能看到正確的效果.
不止寬度
在這裡以"盒模型Hack"達成顯示相同寬度,但是這個Hack其實能在任何想為IE5 for Windows提供不同CSS內容時派上用場.任何Hack都必須小心使用,同時只有在真正需要的時候才使用,記住 "盒模型Hack"的使用地點是個好主意,這樣才能在未來輕易拿掉它.
本文撰寫時仍有上百萬網絡使用者仍然使用IE5 for Windows,因此這個補丁不可或缺.
下面這段"偽裝的欄位"原始出自2004年一月份的A List Apart雜志(http://www.alistapart.com/articles/fauxcolumns/).
偽裝的欄位
關於我個人網站的設計,我最常被問到的問題是:
"你是如何讓右欄的背景色一路延伸到整頁底部的?"
其實這只是個簡單的概念,真的.而且這個概念能應用到本章開始所述的每種布局方法上.
垂直伸展
CSS最容易讓人感到挫折的性質之一,是元素只會垂直伸展到真正需要的長度.這代表如果在<div>裡放一張200像素高的圖片,那麼<div>就只會在頁面上延伸200像素.
當你以<div>切割頁面段落,接著用本章開始時的方法用CSS完成多欄布局時,這就會成為有趣的困境,某一欄可能比其他欄都長(圖12-13),當你想為每欄選用獨特的背景色彩時,視內容多寡而定,做出兩個一樣長的欄位可能十分困難.
圖12-13 長度不一樣的欄位
有幾個做法能讓闌尾看起來一樣長,不受欄位包含的內容的影響.我准備分享我的解決方法(適用於絕對定位布局法),而這個方法實在是莫名其妙的...簡單.
作弊
這個難以啟齒的簡單秘訣,是用一個垂直排列的背景圖片作出彩色欄位的錯覺.在SimpleBits(http://www.simplebits.com/),我用了類似圖12-14的背景圖片(為了示范而修改了比例):左邊有裝飾用條紋,中間留下寬闊的空白空間安放主要內容,接著是一條1像素的邊框,然後是右側邊欄的淺棕色區域,跟著是反向的裝飾用條紋.
圖12-14 tile.gif 2像素高的背景圖片,預先分配好欄寬.
整個圖片沒有幾像素高,但是垂直平鋪之後,他就能造成一路到底的彩色欄位,不管欄位內容多長都無所謂.
CSS內容
我為<body>標簽加上這條CSS規則:
background: #ccc url(tile.gif) repeat-y 50% 0;
這會使整個頁面的背景色設為灰色,並且只垂直平鋪圖片(repeat-y),後面的50% 0代表背景圖片的定位:在這個例子裡,是從浏覽器視窗左邊緣算起50%(使圖片居中),並且緊貼上邊緣.
欄位定位
放好背景圖之後,在把我的定位布局放到上面,為左欄,右欄指定內外補丁以確保它們會對齊正確位置:也就是背景圖創造出來的虛假欄位裡(圖12-15).
圖12-15 平鋪背景圖創造出的彩色欄位
有個重點必須要注意:如果哪一欄指定了邊框,內外補丁的話,就仍然用Tantek Celik的盒模型Hack為IE5 for Windows修正盒模型問題(參照本章稍早的"盒模型問題").
或者是,如果能夠只使用外補丁,避免邊框與內補丁的話,就不需要加上盒模型Hack了,同時,如果欄位的內容只單純放在平鋪背景圖之上(透明顯示),那麼要避免使用Hack也應該很簡單.
只要有用就好
雖然我以絕對定位法在自己的網站上做了兩欄布局,但是你也能用本章開始時提過的其他方法達成一樣好的效果.同樣的想法仍然適用:平鋪背景圖,接著再浮動某個欄位,使其覆蓋在模擬的欄位背景上.
這是個簡單的概念,但是能夠解決設計者在構建CSS布局時經常遇到的挫折之一.
結論
我希望本章能帶給你開始探索CSS布局的刺激世界,本章開始時我們看到了四種構建版面布局的方式,其中三種用了float屬性,還有一種用了絕對定位.一定要去看看我列出的額外資源,裡面有更多布局的技巧和示范.
我們也討論了盒模型Hack在建立具備邊框,內補丁的欄位時有何重要性,讓這些效果在IE5 for Windows以及其他浏覽器上表現一致.
最後,我分享了一個有用的技巧,讓你在設計CSS布局時能做出等高欄位,這是某些人認為十分基本,但實現上經常讓人感到挫折的設計目標.只要小小一個平鋪背景圖就能搞定,讓你得到能夠抵達頁面底部(不管內容多長)的欄位.