作者:Tony Qu
最近有個需求,要求讓頁腳貼底,一開始采用了絕對位置的footer方案(設(shè)置footer的top),雖然可以應(yīng)付大部分情況,但有的時候由于頁面不規(guī)范,會導(dǎo)致計(jì)算出來的高度值太小,導(dǎo)致底部上浮;有的時候甚至?xí)B在頁面內(nèi)容之上。我們原本在onmouseup, onresize, onload中進(jìn)行計(jì)算,但由于系統(tǒng)的龐大,往往會有一些層的onmouseup事件無法傳上來(可能是調(diào)用了stoppropagation或cancelBubble的關(guān)系),有很多未知的情況發(fā)生。
回過頭來說說這個需求的具體要求:
a. 當(dāng)可見內(nèi)容的總高度(不包括頁腳)不超過瀏覽器客戶區(qū)域?qū)嶋H高度時,頁腳要貼在瀏覽器底部,但不能有滾動條
(圖中紅色為屏幕顯示區(qū)域)
b. 當(dāng)可見內(nèi)容的總高度超過瀏覽器客戶區(qū)域?qū)嶋H高度時,頁腳隨內(nèi)容向下
(圖中紅色為屏幕顯示區(qū)域)
其實(shí)是個人第一點(diǎn)想到的就是想辦法計(jì)算除去footer高度的內(nèi)容總高度,問題是總高度怎么算?什么時候算?這確實(shí)是一個值得思考的問題。
總高度的計(jì)算看上去是個很簡單的問題,但實(shí)際情況真的是如此嗎?如果我們自己用遍歷DOM的方法來計(jì)算高度,恐怕很難得出一個準(zhǔn)確的高度,因?yàn)椴⒉皇撬械脑囟家{入高度計(jì)算的(例如加了float的元素、position為absolute的元素)。于是想到了請瀏覽器幫忙,盡量用html DOM原生屬性來解決,這時想到了document或者window的屬性。在IE中,我們找到了document.documentElement.clientHeight(由于我們使用的DOCTYPE是XHTML 1.0的,document.body.clientHeight不能正常工作);而在firefox中,我們找到了window.innerHeight。到目前為止,我們已經(jīng)可以獲得整個頁面的高度了,那去除footer高度的內(nèi)容總高度自然而然就可以用下面的公式來獲得:
去除footer高度的內(nèi)容總高度=頁面總高度-footer的高度
接下來要做的就是把這個高度賦給Content的容器(假設(shè)是一個ID為contentContainer的DIV),請注意這里的Content包括任何除footer以外的東西(包括header)。由于有需求b,我們就得考慮如何讓footer在content超過顯示高度后不會繼續(xù)被看見(浮在頁面底部),所以肯定不能用top或margin-top,查閱css手冊后,發(fā)現(xiàn)有一個屬性最合適——min-height,這個屬性在實(shí)際內(nèi)容不夠時,仍然會保持設(shè)置的高度,超過設(shè)置高度,會自然增加高度,但有一點(diǎn),IE6不支持min-height,經(jīng)實(shí)驗(yàn)表明,在IE6中可以用height代替。
所以我們得到了以下的方案:
var isIE6=navigator.userAgent.indexOf('MSIE 6')>0; var isIE=navigator.userAgent.indexOf('MSIE')>0; ion setFooterPosition() var objBodycontainer = document.getElementById("ContentContainer"); var footerHeight=document.getElementById('FooterContainer').offsetHeight; f(!isIE) if(window.innerHeight > footerHeight) document.getElementById('ContentContainer').style.minHeight = (window.innerHeight-footerHeight)+'px'; lse if(isIE6) { if(document.documentElement.clientHeight > footerHeight) document.getElementById('ContentContainer').style.height = (document.documentElement.clientHeight-footerHeight)+'px'; } else { if(document.documentElement.clientHeight > footerHeight) document.getElementById('ContentContainer').style.minHeight = (document.documentElement.clientHeight-footerHeight)+'px'; } }
最后就是選擇重新進(jìn)行高度計(jì)算的時機(jī),由于我們設(shè)置的是min-height(除了IE6),所以從根本上保證了不需要在內(nèi)容高度改變時重新計(jì)算高度,但有一種情況必須考慮,那就是瀏覽器的客戶區(qū)域大小的改變,所以最后選擇了onresize事件和onload事件。
完整代碼如下:
<!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> </head> <script language="JavaScript"> var isIE6=navigator.userAgent.indexOf('MSIE 6')>0; var isIE=navigator.userAgent.indexOf('MSIE')>0; function setFooterPosition() { var objBodycontainer = document.getElementById("ContentContainer"); var footerHeight=document.getElementById('FooterContainer').offsetHeight; if(!isIE) { if(window.innerHeight > footerHeight) document.getElementById('ContentContainer').style.minHeight = (window.innerHeight-footerHeight)+'px'; } else { if(isIE6) { if(document.documentElement.clientHeight > footerHeight) document.getElementById('ContentContainer').style.height = (document.documentElement.clientHeight-footerHeight)+'px'; } else { if(document.documentElement.clientHeight > footerHeight) document.getElementById('ContentContainer').style.minHeight = (document.documentElement.clientHeight-footerHeight)+'px'; } } } if(isIE) { window.attachEvent("onload",setFooterPosition); window.attachEvent("onresize",setFooterPosition); }else { window.addEventListener("load",setFooterPosition,false); window.addEventListener("resize",setFooterPosition,false); } </script> <style type="text/css"> body { margin:0; } #content { height:300px; background-color:green; } #FooterContainer { height:30px; background-color:red; } </style> <body> <div id="ContentContainer"> <div id="content">aa </div> </div> <div id="FooterContainer"> </div> </body> </html>
另外,這種方法有個小漏洞,如果有些層使用了float,可能導(dǎo)致瀏覽器返回的高度值不準(zhǔn)確,所以必須使用clear大法來解決這個問題,告訴瀏覽器這些float的高度是需要計(jì)算的。
心得:
a. 瀏覽器的很多自帶屬性有時比上層代碼計(jì)算出來的值更加準(zhǔn)確,畢竟是瀏覽器負(fù)責(zé)調(diào)用渲染引擎的,它比誰都了解自己呈現(xiàn)出來的東西
b. 適當(dāng)調(diào)整頁面結(jié)構(gòu)(添加容器),能夠使問題更容易解決。(原本我們的頁面中沒有ContentContainer這樣的同時包含header和content的容器)
如對本文有疑問,請?zhí)峤坏浇涣髡搲?,廣大熱心網(wǎng)友會為你解答!! 點(diǎn)擊進(jìn)入論壇