[轉貼] CSS 排版技巧:上下左右置中、不隨頁面捲動的內容

2012062817:50
出處:http://tw.myblog.yahoo.com/class2u-com/article?mid=2096

大家還記得有一陣子滿流行的網頁廣告,是一張小圖或小區塊在網頁的右上角,當頁面捲動時這個廣告會跟著一起捲動,因此不論頁面捲到哪,廣告都會一直顯示在畫面上、一直都可以看得到。是的,在早期的雅虎奇摩首頁改版之前都還可以看到這樣的廣告呢!在許多其他網站也能看到類似的效果,連小正正 Flash 5 的書的專屬網站都有,只不過那個會跟著一起移動的小區塊放的不是廣告,而是網頁選單。

在以往這樣的效果是使用 Javascript 寫出來的,不但程式碼攏長而且有時還會卡卡的,或造成畫面閃爍。現在有了愈來愈強大的 CSS 以及愈來愈好的瀏覽器支援性,只要幾行簡單的 CSS 語法便能製作出同樣的效果。除此之外,使用相同的 CSS 語法也能製作出類似傳統頁框 (Frame) 的效果呢!就看你怎麼去應用它囉!而這個 CSS 語法的關鍵便是 position:fixed

 

Position is Everything

記得小正正剛開始鑽研 CSS 不久的時候,就拜訪過一個 "聖經" 級的網站,站名很有趣,叫做 Position is Everything (定位就是一切啊!)。這個網站專門探討各家瀏覽器在處理 CSS 定位時的產生的 bug,因為使用 CSS 排版會導致網頁版面亂掉、或是在不同的瀏覽器中看起來不一樣,罪魁禍首幾乎都是這些 bug。如果你想知道 IE 在 CSS 上有那些 bug 以及如何解決,到這個網站去看準沒錯啦!

CSS 有一大堆用來設定文字、顏色、邊框、區塊大小...等等的樣式屬性,而其中一個和排版最有關係的是 position,顧名思義就是設定位置、定位用的。position 這個樣式屬性可以接受五種值:

  • absolute:用來設定相對於頁面或某個元素的絕對座標位置。
  • fixed:相對於瀏覽器視窗的固定座標位置,不會隨著頁面捲動。
  • inherit:繼承,和父元素有相同的值。
  • relative:相對於自己本身的座標位置。
  • static:靜態的,所有元素不指定的 position 時都是屬於這一種。

(註:這裡所說的 "元素" 是 HTML element,也就是 HTML 標籤。)

在之前的文章 "CSS 相對定位技巧" 小正正已經教大家使用過 absolute 和 relative,如果忘記或還沒看過的人趕快去複習一下吧!在這次的範例中,我們所使用到的就是 fixed 這個值,先來看看範例的實際效果吧!

 

基本樣式

首先讓我們來看看頁首的作法,HTML 碼如下:

< div id="fiexd-header">< h1>CSS 範例 - position:fixed 固定位置不捲動的內容< /h1>< /div>

只是一個 div 包著 h1 而已,而且這個 div 的 id 叫做 fiexd-header。在還沒有開始定位之前,先設定一下顏色、大小等基本樣式,讓它漂亮一點。以下是 CSS 的語法:

#fiexd-header{
  background:#66CCCC; /*背景顏色*/
  color:#FFFFFF; /*文字顏色*/
  border-top:2px solid #336699; /*上方邊框*/
  border-bottom:2px solid #336699; /*下方邊框*/
  width:100%; /*寬度*/
}

這段 CSS 語法很簡單,而且都有加上註解,應該沒有什麼問題。有一個小地方要特別注意一下,我們將寬度設為 100% 希望區塊和瀏覽器視窗一樣寬時,就不要再加上左右方的邊框和左右方的邊界 (margin) 了,如果有邊界的話最好設為 0。因為寬度已經 100% 了,如果再加上邊框或邊界的大小時,就會超過 100%,這時瀏覽器就會不知不覺的出現橫向捲軸了!除非你真的希望它有橫向捲軸。

因此在這裡我們特地分開用 border-top 和 border-bottom 去設定上下邊框,不要左右邊框。如果直接寫 border:2px solid #336699 的話上下左右都會有邊框,便會出現討厭的橫向捲軸。

 

用 position:fixed 固定位置

我們希望當頁面內容捲動時,這個頁首的區塊不會隨著一起捲動,能夠在固定的位置一直顯示在畫面上。這時主角登場啦!讓我們幫他加上 position:fixed:

#fiexd-header{
  background:#66CCCC;
  color:#FFFFFF;
  border-top:2px solid #336699;
  border-bottom:2px solid #336699;
  width:100%;
  position:fixed; /*固定位置定位*/
  top:0; /*距離上方 0 像素*/
  z-index:1; /*重疊時會在其他元素之上*/
}

加上 position:fixed 便能讓這個元素固定位置,不會隨著頁面一起捲動,這是標準的 CSS 裡面就有的功能。而我們希望它一直固定在瀏覽器視窗最上方的位置,所以要加上 top:0。再加上 z-index:1 讓它的內容重疊在其他網頁內容之上,不會被蓋掉。

 

修正 IE 6 不支援 position:fixed 的問題

其實正常來說應該做到上面那個步驟就可以了,你使用 IE 7、Firefox 或 Safari 瀏覽器來測試,都已經能夠達到我們想要的效果。但唯獨 IE 6 有問題... 因為在 IE 6 中的 position 根本不支援 fixed 這個值啊!

怎麼辦呢?還好 IE 還有一個特異功能叫做 expression,可以在 CSS 裡面寫程式!我們只好靠這個程式來解決 position:fixed 的問題了:

#fiexd-header{
  background:#66CCCC;
  color:#FFFFFF;
  border-top:2px solid #336699;
  border-bottom:2px solid #336699;
  width:100%;
  position:fixed;
  top:0;
  z-index:1;
  _position:absolute; /* position fixed for IE6 */
  _top:expression(documentElement.scrollTop+"px");

}

首先將 position 設回為 absolute 而不是 fixed,因為只有 IE 6 需要這樣做,所以在屬性 position 前面加了一個底線 (中間不要空格),這種非標準的寫法只有 IE 6 看得懂 _position 代表 position,IE 7、Firefox 和其他瀏覽器都看不懂,便會直接忽略掉這個屬性。這是 IE 6 CSS 的 bug 之一,而這種利用瀏覽器的 bug,寫一些讓某種瀏覽器看得懂、某種瀏覽器看不懂的 CSS 語法,我們稱為 CSS Hack

除了底線以外,CSS Hack 實在太多啦!因為 bug 真的很多,有興趣的人可以搜尋一下關鍵字 "CSS Hack"。不過 CSS Hack 建議盡量少用,能不用則不用,通常是非不得以才去使用它的。因為 CSS Hack 屬於 bug 的一種,當瀏覽器改版升級後,bug 便消失了,以前看得懂的 CSS Hack 語法可能變成看不懂了,或以前看不懂得可能變成看得懂了!如果你在網頁中使用了大量的 CSS Hack,那麼用新版本的瀏覽器來看原有的網頁,會變得亂七八糟的原因之一有可能就是因為 CSS Hack。有些人會覺得使用 CSS Hack  很神,好像代表自己很厲害,但是小正正並不希望大家太用心去研究 CSS Hack,只要知道幾個基本的能應付目前的狀況就可以了,不然等到 IE 8 一出來時又要死一堆網頁、又得花一堆時間來抓蟲蟲了!

哇~ 題外話太多讓我們回到正題,針對 IE 6 設定 _position:absolute 之後,光靠 top:0 將頁面對齊上方是不夠的,當頁面捲動時頁首仍然會跟著一起跑出畫面不見。所以我們針對 IE 6 將 top 的值設為一段 expression 程式,而程式的內容就是取得頁面捲動後最上方的座標值 documentElement.scrollTop 再加上 "px" 這個字串:

_top:expression(documentElement.scrollTop+"px")

不論頁面捲到哪,讓頁首的 top 一直保持在捲動後視窗最上方的位置,看起來的效果就像是頁首一直保持在畫面的上方不動了,事實上頁首相對於整個文件最開頭的座標是一直在改變的,由這段 expression 程式來處理。

這段 expression 是針對 IE 6 才需要使用,IE 7 不需要,所以屬性 top 的前方也是加了底線。小正正再次提醒你,CSS Hack 盡量少用,還有 expression 也是一樣的,它是非標準的東西。想當年 IE 7 剛出來時,小正正將 Yahoo! 許多網頁改版成讓 IE 7 能正常瀏覽,一大半的問題都是出在 expression,而另一小半的問題幾乎就是 CSS Hack 了。

 

修正 IE 畫面閃爍的問題

這時用 IE 6 來測試結果,頁首就已經能夠一直保持在瀏覽器視窗的上方了,但捲動頁面內容時頁首卻會一跳一跳或出現閃爍的情況,這又是 IE 的另一個 bug 了!(IE 真是蟲蟲危機啊~)解決的方法很簡單,在原有 CSS 的前面加上另一段 CSS:

html,body{
  background:url(nothing.txt) white fixed; /* prevent screen flash in IE6 */
  margin:0; padding:0;
}

幫 html 和 body 這兩個元素加上一個固定不動的背景圖片,而且背景圖的 url 隨便給一個不存在的檔案也沒關係,這樣就自然而然解決了頁面捲動時頁首閃爍的問題了!傑克,這真是太神奇啦!小正正也不知道為什麼,就當做以毒攻毒,用 bug 去解決另一個 bug 吧!Orz...

在這裡我們也將 html 和 body 的邊界和間距設為 0,讓頁首可以完全靠上對齊。到這裡頁首的部份就全部完成啦!

 

position:fixed 時的置中對齊

接著來看正中央那個上下左右都置中對齊的內容區塊,HTML 碼是這樣的:

< div id="fixed-center">
  < h2>這是上下左右都置中對齊的區塊< /h2>
  < p>這個範例使用 IE6, IE7, Firefox 2, Firefox 3 和 Safari 3 (Mac版) 測試過...... < /p>
< /div>

首先一樣先設定基本的外觀樣式,CSS 語法如下:

#fixed-center{
  background:#FFFF99; /*背景顏色*/
  color:#FF6600; /*文字顏色*/
  font-weight:bold;  /*粗體字*/
  border:1px solid #990000; /*四周邊框*/
  padding:10px; /*內距*/
  width:400px; /*寬度*/
  height:200px; /*高度*/
}

再來一樣用 position:fixed 來做定位,讓它不會因為頁面捲動而移動位置。並且讓它上下左右都能置中對齊:

#fixed-center{
  background:#FFFF99;
  color:#FF6600;
  font-weight:bold;
  border:1px solid #990000;
  padding:10px;
  width:400px;
  height:200px;
  position:fixed; /*固定位置定位*/
  top:50%; /*距離上方的位置*/
  left:50%; /*距離左方的位置*/
  margin-top:-100px; /*上方邊界*/
  margin-left:-200px; /*左方邊界*/
}

當 position 為 fixed 時,要左右置中的作法和平常不太一樣。如果你看過小正正之前的教學,還記得平常左右置中的寫法是 margin:0 auto,將左右兩側的邊界設為自動。但在 position 為 fixed 時這樣寫是沒用的,要改為 left:50% 距離左方 50% 的位置,這時元素就會被定位到頁面的正中央 (如果頁面寬度是 800px,會被定位到 400px 的位置)。但定位是根據元素左上角的座標,不是元素中心點的座標,所以我們必須把元素本身的寬度考慮進去,再加上 margin-left:-200px 把左邊界設為負的 200px,讓元素往左移動 200px。因為元素的寬度是 400px,所以設為 200px 剛好是一半,便能讓元素的中心點和頁面正中央對齊了。想像一下,left:50% 先將元素的左側對齊頁面正中央了,再用 margin-left:-200px 將元素向左移動一半,讓中心點對齊頁面正中央。

上下居中也是一樣的,top:50% 先將元素的上方對齊頁面正中央了,再用 margin-top:-100px 將元素向上移動一半 (元素高度為 200px),讓中心點對齊頁面正中央。

到這裡 IE 7 和 Firefox 等支援 position:fixed 的瀏覽器都 OK 了,剩下的就是處理 IE 6 的部份。和前面相同,用底線的 CSS Hack 再加上 expression,因為對齊的座標位置不同,所以 expression 的程式會有小小的不同:

#fixed-center{
  background:#FFFF99;
  color:#FF6600;
  font-weight:bold;
  border:1px solid #990000;
  padding:10px;
  width:400px;
  height:200px;
  position:fixed;
  top:50%;
  left:50%;
  margin-top:-100px;
  margin-left:-200px;
  _position: absolute; /* position fixed for IE6 */
  _top:expression(documentElement.scrollTop+(documentElement.clientHeight-this.clientHeight)/2);
  _margin-top:0;

}

不論頁面怎麼捲動,元素都要上下置中對齊,座標的計算方式是瀏覽器視窗的高度 (documentElement.clientHeight) 減去元素的高度 (this.clientHeight) 除以二後再加上頁面捲動後最上方的座標值 (documentElement.scrollTop)。而且這時 top 距離的位置已經由 expression 計算好了,不是 50% 了,就不需要再加上個負數的邊界來做調整,因此再加上 _margin-top:0。

 

靠右對齊

靠右上方對齊的那個小區塊,很類似早期雅虎奇摩首頁十分流行的一種廣告。它的 HTML 碼如下:

< div id="fixed-ad">這是廣告< /div>

CSS 的部份和其他區塊幾乎都一樣,沒什麼特別的,不同的只有對齊位置用的 top、right 樣式屬性和 expression 的寫法:

#fixed-ad{
  background:#FF0066;
  color:#FFCC99;
  border:4px solid #FF9999;
  padding:5px;
  width:80px;
  height:120px;
  position:fixed;
  top:100px;
  right:10px;
  _position: absolute; /* position fixed for IE6 */
  _top:expression(documentElement.scrollTop+100);
  z-index:3;
}

 

靠下對齊

最後是靠下方對齊的頁尾區塊,幾乎都是用相同的手法,只要注意對齊位置用的樣式屬性 bottom:0 和 expression 即可。HTML 碼如下:

< div id="fixed-footer">製作:< a href="http://www.class2u.com">小正正教室< /a> ......< /div>

CSS 如下:

#fixed-footer{
  background:#CC99CC;
  color:#333333;
  text-align:center;
  border:2px solid #999999;
  padding:5px;
  width:600px;
  position:fixed;
  bottom:0;
  left:50%;
  margin-left:-300px;
  _position: absolute; /* position fixed for IE6 */
  _top:expression(documentElement.scrollTop+documentElement.clientHeight-this.clientHeight-4);
  z-index:4;
}

和頁首不同的是,頁尾的寬度是固定的,並且左右置中對齊,所以會加上 left:50% 和 margin-left:-300px。當然,你想要修改為 100% 的寬度也很簡單,相信看到這裡你應該已經能夠自行變化調整了吧!而在 expression 的最後有一個 -4,是因為頁尾的上下各有 2px 的邊框,所以在計算座標時別忘了將邊框的大小也算進去。