這部分最後給出的成品效果比較驚人,也就是傳說中的純CSS六級菜單。這個東西最厲害的地方是相容所有主流瀏覽器(IE6,IE8,Maxthon2.5,firefox3.5,opera10,safari4與chrome2),而一點CSS hack也沒有用。畢竟CSS hack只是權宜之計,治標不治本,誰知它會對未來新版本的瀏覽器有什麼副作用,因此能不用就不要用了。由於結構非常有規律,讀者認真學習後,可以自行擴充為十級菜單。
司徒正美 純CSS多級菜單
由於IE6能支援的偽類少得可憐,僅支援a元素的hover與visited與active。為了顯示隱藏的二級菜單,我們必須把二級菜單的那個無序列表放到a元素下,但這樣一來firefox那邊又發難了。這時我們就要請出IE的條件注釋,讓頁面在IE6下呈現一套結構層,在其他瀏覽器下呈現另一套。
<p class="menu"> <ul> <li> <a href="http://www.cnblogs.com/rubylouvre/">菜單三<!--[if !IE 6]><!--></a><![endif]--> <ul> <li><a href="http://www.cnblogs.com/rubylouvre/">二級菜單_11</a></li> <li><a href="http://www.cnblogs.com/rubylouvre/">二級菜單_12</a></li> </ul> <!--[if lte IE 6]></a><![endif]--> </li> <li> <a href="http://www.cnblogs.com/rubylouvre/">菜單二<!--[if !IE 6]><!-->二</a><![endif]--> <ul> <li><a href="http://www.cnblogs.com/rubylouvre/">二級菜單_11</a></li> <li><a href="http://www.cnblogs.com/rubylouvre/">二級菜單_12</a></li> </ul> <!--[if lte IE 6]></a><![endif]--> </li> <li> //************略*********** </li> <li> //************略*********** </li> </ul> </p>
但是這樣做不能使IE6的二級菜單彈出來,這情形我在純CSS相簿遇到許多次。查一下國外的資料,說是IE用hover切換絕對位置子項目時存在問題,但具體情形又分許多種,解法也不一。但針對多級菜單的這種多層子項目,最常用的方法是把它們套在table中,這相當於table布局。因為table的容錯能力是最強的,這多得人們一直用它來布局,於是瀏覽器一直在增強它在這方面的優勢。感謝table,我們終於收拾IE6這個怪胎了。
<p class="menu"> <ul> <li> <a href="http://www.cnblogs.com/rubylouvre/">菜單<!--[if !IE 6]><!--><strong>一</strong></a><![endif]--> <table><tr><td> <ul> <li><a href="http://www.cnblogs.com/rubylouvre/">二級菜單_11</a></li> <li><a href="http://www.cnblogs.com/rubylouvre/">二級菜單_12</a></li> </ul> </td></tr></table> <!--[if lte IE 6]></a><![endif]--> </li> <li> <a href="http://www.cnblogs.com/rubylouvre/">菜單<!--[if !IE 6]><!--><strong>二</strong></a><![endif]--> <table><tr><td> <ul> <li><a href="http://www.cnblogs.com/rubylouvre/">二級菜單_11</a></li> <li><a href="http://www.cnblogs.com/rubylouvre/">二級菜單_12</a></li> </ul> </td></tr></table> <!--[if lte IE 6]></a><![endif]--> </li> <li> //*************略************** </li> <li> //*************略************** </li> </ul> </p>
但這樣一來對firefox等瀏覽器添加了許多多餘的結構層代碼,它們基本不需要table這東西就能運作良好。因此,我們把table整到IE條件注釋中。如:
<p class="menu"> <ul> <li> <a href="http://www.cnblogs.com/rubylouvre/">菜單 <!--[if !IE 6]><!--><strong>一</strong></a><![endif]--> <!--[if lte IE 6]><table><tr><td><![endif]--> <ul> <li><a href="http://www.cnblogs.com/rubylouvre/">二級菜單_11</a></li> <li><a href="http://www.cnblogs.com/rubylouvre/">二級菜單_12</a></li> </ul> <!--[if lte IE 6]></td></tr></table></a><![endif]--> </li> <li> //*************略************ </li> <li> //*************略************ </li> <li> //*************略************ </li> </ul> </p>
然而,這結構層還能進一步精簡。同時我們應該留意到IE6水平菜單的異常高度,這是IE6的li元素在包含塊級顯示元素時會多出5px空隙。由於li元素包含的結構比較複雜,以前用對付img元素的幾種方法行不通了。我們可以顯式設定a元素的高度,讓多餘的部分隱藏掉就是。這就唯一不用CSS hack的方法。
更精簡的結構層:
<p class="menu"> <ul> <li> <!--[if lte IE 6]><a href=""><table><tr><td><![endif]--> <a href="http://www.cnblogs.com/rubylouvre/">菜單一</a> <ul> <li><a href="http://www.cnblogs.com/rubylouvre/">二級菜單_11</a></li> <li><a href="http://www.cnblogs.com/rubylouvre/">二級菜單_12</a></li> </ul> <!--[if lte IE 6]></td></tr></table></a><![endif]--> </li> <li> //***********略********* </li> <li> //***********略********* </li> <li> //***********略********* </li> </ul> </p>
.menu a { display:block; /*position:relative;發現放在a元素中, 在標準遊覽器中慘不忍睹, 和純CSS相簿3的第一個運行框在chrome中遇到的bug一樣*/ height:32px; width:100px; line-height:32px; background:#a9ea00; color:#ff8040; text-decoration:none; text-align:center; overflow:hidden;/*★★★★*/ }
基於上面的結構我們就可以開發多級子功能表了。
這時我們又發現在IE6下,當我們的滑鼠移到二級菜單的上面時,一級功能表項目會出現一個邊框,顏色為hover時的背景色。在IE6,table與儲存格之間(cellspacing),儲存格與儲存格的內容之間(cellspadding)是存在空隙,背景色為transparent,也就是說永遠顯示下一層的背景色。由於我們設定a的display:block,它會佔滿td的所有空間,因此那個神秘的邊框應該是cellspacing。我們可以用以下的方式證實我的猜想。
.menu table { border:1px solid aqua; } .menu table td{ border:1px solid aqua; }
知道問題的所在,我們就可以對症下藥了。解決方案有二。一是設定cellspacing等於零。由於cellspacing為DOM屬性,非CSS屬性,換言之,有多少個table我們就要寫多少次。二是設定border-collapse 為collapse,因為這樣會把table與它裡面的td的border合而為一,這樣它們之間的空隙也不複存在。我們當然選擇第二種啦。
.menu table { border-collapse: collapse; }
最後總結一下:
保證hover時,對應的子功能表的top與left在包含塊的範圍內。
通常我們是用hover來調用display實現子項目的隱現,但在IE6中,mouseout後它不會乖乖消失,得換visibility上陣。
某些瀏覽器在用a:hover來切換絕對位置子項目存在bug,統一用li:hover實現。
在IE6中,啟用父級元素的a:hover後再調用其子孫元素的a:hover時,會沒有反應,換言之,不繼續向下渲染。這時我們需要table這個容錯能力最強的標籤出馬。
為了跨平台的需要,我們需要用到IE條件注釋來切換相應的結構層代碼。
在IE6中,當li元素包含display為block的元素時(如a)會多出5px,我們可以用overflow:hidden收拾之。
在IE6中,table與td是存在空隙,當我們移動某個子功能表項時,其父功能表項目就會因為這些透明的空間而染上兩條邊。解決方案:設定table的border-collapse為collapse。