本導覽功能表想達到的理想目標是:
1.漂亮,有個性。
2.結構清晰,語義明確,無冗餘標籤。
3.表現、結構、行為三層分離,無侵入式。
4.有利於背景程式的資料輸出。
5.菜單有三態效果的變化。
6.能高亮記錄點擊後的功能表項目。
7.自適應文字的寬度。當文字內容長短變化時按鈕能適時變化。
8.相容各大主流瀏覽器。
讓我們一步一步的實現這種理想的菜單吧!
在論壇中經常看到很多朋友在製作菜單,但說實話,不是結構冗餘,就是有形無神,或有神無貌。而我們現在要打造的就是極品菜單。無論您是新手或老手,在這個教程中都應該有所收穫。
一個理想的菜單其結構應該是乾淨的、無冗餘、分離的,然而因為種種的原因,會為它加上許多無意義的東西,到最後,會離“乾淨”越來越遠。所以在做菜單前,有些原則是在整個製作過程一直要牢記的,不能以任何外力所阻擾。
結構篇
在我的印象中,理想的標準菜單應該具有下面的結構:
<div id="nav">
<ul id="menu">
<li><a href="#none" title="部落格園">部落格園</a></li>
<li><a href="#none" title="社區">社區</a></li>
<li><a href="#none" title="首頁">首頁</a></li>
<li><a href="#none" title="新隨筆">新隨筆</a></li>
<li><a href="#none" title="聯絡">聯絡</a></li>
<li><a href="#none" title="管理">管理</a></li>
<li><a href="#none" title="訂閱">訂閱</a></li>
<li><a href="#none" title="冰極峰">冰極峰</a></li>
</ul>
</div>
菜單的最原始的結構有了,可以看到這裡面是沒有任何無意義的標籤,每個標籤都有各自的語義。我們在瀏覽器中看下,啊哦,確實很簡陋,就是原始的文字,像什麼,嗯,就像我們在菜館裡點菜用的菜單,可能比那個還簡單,並且每個菜單前面還有一個小圓點!哦,天啦,離我們的漂亮菜單還差好大一截呢!
樣式篇
好吧,它現在還只是一個骨架,我們稍微給它美化一下,加點簡單的樣式,至少應該去掉小圓點吧,並且讓它水平排列吧!
好,加點樣式:
*{margin:0;padding:0;}/*將它統一成一個模樣吧,不然在各個瀏覽器下,會死得很難看*/
ul{list-style:none}/*去掉小圓點吧*/
li{float:left;margin-left:10px;}/*水平排列並來點間距吧,不要把我擠得太緊了。*/
嗯,現在看看,達到小目標了。
骨架有了,接下來就是給每個功能表項目穿上漂亮的衣裳。
要滿足第一項要求,首先要有一個漂亮的按鈕,自已畫一個,哦,我不是美術人員,難!不過,別恢心,網路之大,無奇不有,說不定人家已經有做好的,google一下,還真發現了一個,感謝啊!
有了設計好的按鈕源碼,省去設計的一環,真好。但要做成三態按鈕,還需要我們改造一下這個按鈕。看到第七條目標了嗎,我們是要做自適應的按鈕,所以要對這個按鈕做一些加工處理。
我們將這三個按鈕分別表現為滑鼠移開、點擊後、滑鼠移上時的三種狀態,要做滑動門菜單,需要將一個按鈕從中間剖開,左邊圖處放在左側,右邊圖片放在右側。要適應文字加長的情況,還要將這個圖層寬度拉長一點,但這個圖片有很複雜的陰影特效,不能隨便展開,否則效果就不像了。我們就從中間給它剖開,將右邊圖片的左側向前平輔展開。二所示
圖一
所以我們先將它哪樣切成六片,然後將這六張圖片合并在一起。為什麼要這樣呢?看看css sprites原理吧!
圖二
中第一和第二個圖片組成普通菜單樣式(預設樣式),第三、第四個圖片組成翻滾樣式,第五和第六個圖片組成點擊後的功能表項目樣式。
我們將陰影圖片專門提取出來,作成一張很小的背景圖片。
圖三
該要的圖形都準備好了,接下來,我們將這個圖片加在功能表項目上吧。一個按鈕要用到兩張圖片才能表現出來。地球人都知道,一個標籤只能裝一張圖片(如果你發現一個標籤能裝上兩張圖片,請及時告訴我,我請你吃飯!)。哦!我的菜單結構中每一項剛好有兩個標籤,一個是li,它裡面有一個A標籤,剛好可以用來裝左右兩張圖片。Li用來裝左側的圖片,A用來裝右側的圖片。我真佩服我自己,這麼好的點子都能想得出來,正在沾沾自喜的自我陶醉中…
別忙,哦,天啦,如果這樣來裝圖片,我的三種滑鼠翻滾狀態如何??我們都應該知道,目前除了該死的IE6,其它的瀏覽器都支援li:hover偽類。然而要相容各主流瀏覽器(這是我們的第8項目標喲,別忘了!),這種方法是行不通的。IE6隻能在A標籤上應用偽類,其它的標籤它可是一概不理!
既然IE6隻能在A標籤上應用hover偽類,那麼我們要製作自適應的滑動門菜單,就需要在結構上動手腳了,看來只能在A標籤中再加入一個標籤,那麼菜單的結構就會變成下面這個樣子了。(注意:這兒就開始改變結構了,雖然我一直想極力避免這種情況的發生,但好像要達到要求,這個標籤是非加不可了。)
<li><a href="#none" title="冰極峰"><span>冰極峰</span></a></li>
我們在A標籤中加入了一個span容器,它將文字內容包括起來了。現在有兩個標籤,可以裝兩張圖片了。我們將右側圖片放在A標籤的背景中並向右靠齊,將左側圖片放在SPAN標籤中並向左靠齊。這樣就能表現出一個完整的按鈕形狀。
還好,雖說多加了一個標籤,但它還不是完全無語義。
好了,我們的準備工作都差不多了,該給菜單穿上新衣服了。
我們要做成自適應寬度的菜單,那麼,我們就不能設定菜單的寬度值,所以我們不能像平時製作一個水平的有固定寬度的菜單的做法那樣,設定寬度,然後向左浮動。如果這樣的話,每個功能表項目的寬度不同時,要分別定義每一項的寬度,那就必須給每個功能表項目定義一個ID或CLASS,並且這種方式也不利背景程式的動態迴圈輸出。
我們需要的是像內嵌元素一樣從左至右自動在一行內排列每個功能表項目,那麼我們就需要菜單以內聯的方式表現出來,OK,我們就用display:inline吧,這是一個非常有用的屬性:它解析後的相片順序能達到我們的基本要求:在一行內從左至右自動排文標籤元素,每一項寬度可以不同。
如果用上面這種屬性真的能滿足我們需要了,就沒有下面這一段文字內容。
雖說這個屬效能滿足我們項目基本需要,可是它有一個非常致命的弱點:它不能設定寬度和高度值,不信你可以試試。它只表現為文字的預設高度和寬度,超出這個寬高值後就自動隱藏了。這樣一來,我在這裡面是有背景圖片的,要表現出這個圖片效果,我們需要給定一個寬度和高度。這就不能做出我們的效果了,鬱悶!還好,還有一個屬性:display:inline-block;它的表現就是我們需要的。
但是…這個屬性也有致命弱點,它只能被FF3等進階瀏覽器識別。其它的瀏覽器只能繞道而行了。啊哦!所以,統一瀏覽器是多麼的重要啊!看來,HACK也是我們逼不得已的一種解脫方式了。
原理我們都瞭解了,我們可以根據上面兩篇文章提供的技巧來做一個自適應的菜單了。
我們先寫右側圖片的樣式,它是應用在li元素的子節點A標籤中的。
li a{display:inline-block; padding-right:30px; padding-top:10px; *padding-top:0; padding-bottom:13px; *padding-bottom:0; height:36px; background:url(images/button.gif) no-repeat right -36px; text-decoration:none; font-size:12px; color:#fff;}
我們先設定display:inline-block,然後我們再用padding來撐開它的邊距,讓它有一定的空間來裝填圖片。注意,這裡的圖片路徑換成你自己的路徑。然後設定其它的樣式,如去掉底線,字型顏色,字型大小等等。設定圖片靠右對齊。
li a span{display:inline-block; padding-left:30px; padding-top:10px; *padding-top:0; padding-bottom:13px; padding-bottom:0; height:36px; line-height:36px; background:url(images/button.gif) no-repeat left top; font-weight:bold;}
按鈕左側的圖片是放在SPAN元素中的,將它的圖片向靠左對齊,也設定padding來撐開它的寬度和高度。
li a,li a span{display:inline;cursor:pointer;}
然後將它們的又設定回inline內聯模式,觸發IE的haslayout特性。
在上面的代碼,我們還看到有一個HACK的應用,*padding-bottom:0;和*padding-top:0;這用來解決IE與FF等瀏覽器不同效果的。不信你刪除後看看會有什麼效果,在IE下高度伸展有問題。
好了下面該寫滑鼠移上時的效果了。
li a:hover{padding-right:30px;background:url(images/button.gif) no-repeat right -108px;}
li a:hover span{padding-left:30px;background:url(images/button.gif) no-repeat left -72px;font-weight:bold;}
再接下來是滑鼠點擊後的效果。
li a:active{padding-right:30px;background:url(images/button.gif) no-repeat right -180px;}
li a:active span{padding-left:30px;background:url(images/button.gif) no-repeat left -144px;font-weight:bold;}
ok,似乎大功告成,在不同瀏覽器下看看,似乎都能達到滿意的效果。下面是:
圖四
現在純CSS版的滑動門菜單基本上就做好了。
行為篇
上面的效果似乎離我的理想狀態的菜單又更進了一步。不過也有暇癡。
1.如我點擊一個菜單後其焦點虛線框讓人感到非常討厭。
2.還有點擊後不能高亮記錄當前選中項。
一步一步來解決吧!
為了除去此虛線框,我們可以在A標籤屬性中加入onfocus="this.blur();"這句代碼,這是非常立竿見影的方法。那麼就需要在結構上添加一些內容,可能就會變成下面這種結構了:
<li><a href="#none" title="冰極峰" onfocus="this.blur();"><span>冰極峰部落格</span></a></li>
可是,我們別忘了,要盡量避免“行為”給“結構”造成幹擾,這是我們在開始就提出的要求。因此,這種方法基本上可以否決了。
另外我們想記錄當前選中項菜單,這種製作方法有很多種,純CSS的做法可能會為每一個功能表項目建立一個ID,然後用樣式表來設定不同頁面下調用高亮菜單的樣式。但這種方法又會對結構添加一些字元。
上面兩個解決方案都需要在結構中嵌入一些本來該用“動作”來表現的東西,這會造成結構冗餘,可讀性較差,並且給人感覺頁面很亂。
我想該是JS粉墨登場的時候了...
我想在頁面一載入時就遍曆UL下的所有A標籤,自動給它加上一個樣式,這個樣式就是li a的樣式,我們可以將它改成一個class類,我們取名為normal吧,方便JS動態調用,並將li a:hover也換成一個class類,取名為over,作為JS動態調用滑鼠移上時的效果,而li a:active就是當前選中狀態了,取名為cur,將它們三個都在樣式表中作出修改。
在頁面載入後,用for迴圈給每個菜單A標籤注入onclick,onmouseover,onmouseout事件,我們就可以摒棄用a:link,a:hover,a:active來摸擬三態效果了,因為這樣更便於控制當前選中菜單的高亮效果。順便在這個迴圈中去掉討厭的虛線框(雖說在FF下只用一句樣式就可以搞定,但在IE中顯然是不行的!)。然後我們用cookie來記錄選中的功能表項目ID,並設定其為5分鐘後到期。這樣無論你如何惡意刷屏,高亮菜單還是能記住。(是否採用cookie方式來保持高亮,這可以根據不同的項目需求來定。這種方式也有不好的地方,有同好者可以交流一下!)
Js中建立了幾個基本的函數,看起來就像下面這樣(詳細代碼請參看源碼):
var temp;/*菜單ID*/
function getObj(objName){return(document.getElementById(objName));}
window.onload =function() {
var obj=getObj("menu");/*ul的id*/
var obj_a=obj.getElementsByTagName("a");
number=obj_a.length;
for (var i=0,j=obj_a.length;i<j;i++){
obj_a[i].index=i;
obj_a[i].className="normal";
obj_a[i].onclick=function(){click(this)};
obj_a[i].onmouseover=function(){overme(this)};
obj_a[i].onmouseout=function(){outme(this)};
obj_a[i].onfocus=function(){this.blur()};/*去掉IE下的虛線框,ff用樣式解決*/
}
if (getCookie("show_a") != null) {
obj_a[getCookie("show_a")].className="cur";
temp=getCookie("show_a")
}
else{
var obj=getObj("menu");
var obj_a=obj.getElementsByTagName("a");
obj_a[0].className="cur";
//滑鼠滑過效果
function overme(o){/*代碼略,請看DEMO*/}
//滑鼠移開後效果
function outme(o){/*代碼略,請看DEMO*/}
//滑鼠點擊後效果
function click(o){/*代碼略,請看DEMO*/}
//設定cookie
function setCookie(sName,sValue,expireMinute) {/*代碼略,請看DEMO*/}
//擷取cookie
function getCookie(sName) {/*代碼略,請看DEMO*/}
加上以上的js後,我們控制了菜單的互動動作,並精簡了菜單的結構,三層分離得比較徹底。這樣結構未做作何過多的變動,就達到我們理想的狀態。這樣的結構在添加後台代碼時,直接迴圈,只需要在菜單文字項的地方動態輸出資料就行了,乾淨利落。
現在在各種主流瀏覽器中看看你的成果,是否顯示得完全一樣呢!
圖五
至此,一個極酷的標準的滑動門導覽功能表就在你手中誕生了!
總結:我們在製作這些案例時,要隨時留意自己的結構,讓它能保持良好的前後伸展性。盡量杜決冗餘的無語義的標籤,這在一個流水線似的工作環境中尤其顯得重要。給後端程式帶來巨大的方便的同時,也使自己的代碼看來比較舒服!
本執行個體測試的相容性環境是:
IE6/IE7/FF3/TT/OPERA9.63/Google瀏覽器測試通過,其它的瀏覽器請朋友幫忙測試一下。