樹狀選單加入樹狀線條的設計
- 說明:設計具有樹狀線條的資料夾選單或樹狀選單 (folder menu or tree menu)。本篇的討論僅適用一層子選單,更多層子選單的設計方式,以後再討論。
- 適合:有設計網頁及撰寫 css 語法經驗者。
- 難度:
- 更新:
以下將會討論如何巧妙運用 css 基本特性 (property) 來完成這個實例。
- 先了解
xhtml這部分內容的安排。 -
<div class="TreeMenu"> <div class="section"> <h1>古文今讀</h1> <ul> <li><a href="#">上古神話</a></li> <li><a href="#">詩經</a></li> <li><a href="#">楚辭</a></li> <li><a href="#">諸子散文</a></li> <li><a href="#">漢賦選輯</a></li> <li><a href="#">樂府</a></li> <li><a href="#">駢文</a></li> <li><a href="#">唐詩</a></li> <li><a href="#">宋詞</a></li> <li><a href="#">元曲</a></li> <li><a href="#">章回小說</a></li> </ul> </div> <!--.section--> <div class="section"> <h1>現代文藝</h1> <ul> <li><a href="#">小說</a></li> <li><a href="#">散文</a></li> <li><a href="#">性靈小品</a></li> <li><a href="#">新詩</a></li> <li><a href="#">翻譯小說</a></li> </ul> </div> <!--.section--> </div> <!--.TreeMenu-->
本篇範例的完整 css 設計內容。
思考 - css 設計的構思與佈局
我們儘量以探討方式介紹,引導如何構思及擴展 css 設計,希望能激發更多設計想法為主,避免陷入步驟式或教條式的悲慘學習模式。
開始:定義一些基本的 css 設計
最外圍的 .TreeMenu 指定寬度 (width) 、背景顏色 (background)、邊線 (border) , 而 h1 指定字體大小 (font) , a 去掉底線, ul, h1 去除周圍距離 (padding, margin) 等等。
css-
h1, ul { margin: 0; padding: 0; } .TreeMenu { width: 10em; background: rgb(92%,86%,100%); border: 1px solid rgb(60%,60%,80%); } .TreeMenu .section h1 { font-size: 100%; font-weight: normal; } .TreeMenu .section ul { list-style: none; } .TreeMenu .section li a { text-decoration: none; }
line-height (行高) 是設計的主要概念
視覺性的瀏覽器通常會預先賦予每行「大於一個字」的行高 (line-height) ,為了避免不同瀏覽器間產生的差異,以及後面設計 css 時有所依據,先將整個選單內 line-height 定義為「字高度」的倍數,例中為 1.1 倍,看起來行距應該會較原來更緊一點。由於 line-height 特性 (property) 有繼承性 (inheritance) ,所以只需要定義一次在 .TreeMenu 或 .section 就可以;這裡也順便為分類標題 h1 加背景色修飾一下。
- 接續前面,增加 一點
css定義 (紅字) -
.TreeMenu .section { line-height: 1.1; } .TreeMenu .section h1 { font-size: 100%; font-weight: normal; background: rgb(85%,70%,90%); }
我們只以倍數定義行高,也沒有指定字體的尺寸 (font-size),如此是為了使全部的設計,單純地以字高 (em) 的倍數來計算,不用去管字體到底幾個像素 (pixel) 大,或者一行有多少像素高。想指定 font-size 當然可以,不過行高最好還是以倍數的方式指定,設計時才不至於太難計算;這只是建議囉,全部都用像素為單位也沒問題,計算清楚,小腦袋瓜別爆掉就好。
產生樹狀的垂直線條
在 ul 左側加上線條,當做樹狀結構的垂直線,並且左邊空出一點距離,讓子選項內容 li 看起來向內縮排。這個距離應該是要對應分類標題 h1 來設計,我們指定了向內縮半個字 (0.5em),所以線看起來像是由標題第一個字中間向下延伸;標題最前面如果變成小圖示 (icons) ,那就以圖示寬度的一半去定義縮排距離也可以。這裡應該以 margin 來指定內縮距離,因為我們必須讓垂直線緊貼著 li 。線條寬度沒有使用 em 定義,是因為 1px 寬幾乎沒什麼影響,但是如果需要設計較粗的線,單位最好一致。
- 在前面已指定的
ul增加css定義 (紅字) -
.TreeMenu .section ul { list-style: none; margin-left: 0.5em; border-left: 1px dotted; }
我們沒有特別指定線條 border 的顏色,將會與該區域字的顏色相同,如果想另外定義顏色,可以像這樣,
border-left: 1px dotted rgb(255,0,0);
線條要改成實線也可以, dotted → solid ,當然其它形式的線條也可有更多變化。
產生樹狀的水平連接線條
在子選項 li 下方加上線條,當做樹狀結構子選項的橫連接線。這裡也讓 li 的內容 a 向內縮排,不過,不同於前面,我們必須保持每個 li 下方的線與左側 ul 的線緊緊相接,所以在 li 指定 padding ,僅讓內容 a 向內縮,但 li 本身沒有縮排。
- 接續前面,增加
li的css定義 -
.TreeMenu .section li { padding-left: 0.5em; border-bottom: 1px dotted; }
border 也沒有特別指定顏色,這樣可以對應前面 ul 的 border 顏色,如果想另外定義顏色,方法同前。
css position:relative; 讓 a 向下位移 (offset)
css position:relative; 主要的特點就是,元素可以由本身的 Box 位移,並且保留其它元素原來的排版。利用這個特點,只要讓 a 向下位移半行,而 li 會維持原來的位置及下方的橫線, a 的中間就會剛好壓在 li 的線上。前面已經指定 line-height:1.1; (1.1倍的字高),所以半行就是 0.55em ,太棒了,只有 a 向下移,所有 a 以外的東西都不會動。
- 在前面已指定的
a增加css定義 (紅字) -
.TreeMenu .section li a { text-decoration: none; position: relative; top: 0.55em; }
由於水平線條只有 1px 厚度,對整個位置並無影響,可以不需考量;但是如果指定了較粗的線條,就需要顧慮到線條的厚度會佔掉空間,向下位移的距離應該多加半個線的厚度,這也是為什麼前面有提醒要注意單位一致的原因,如果線的單位是 px ,而行高是 em,那還真有點難算。
背景顏色蓋掉重疊的線
明顯地,現在面臨兩個問題:一、字的背面不應該有線。二、因為 a 的向下位移,造成與下一個分類重疊。第二個問題稍後再討論。第一個問題比較容易處理,我們為 a 指定背景色就可以蓋住 li 的橫線了,由於 a 本身為行內層級元素 (inline-level elements) ,所以背景色只會在有字的區域呈現。如果 a 不想有背景顏色,只要指定與 .TreeMenu 相同的背景色, a 看起來就像沒有背景色的樣子。
- 在前面已指定的
a增加css定義 (紅字) -
.TreeMenu .section li a { text-decoration: none; position: relative; top: 0.55em; background: rgb(80%,85%,100%); }
如果想讓字之後的整條線都蓋掉,只要把 a 轉換成區塊層級 (block-level) 呈現即可。
- 繼續為
a增加css定義 (紅字) -
.TreeMenu .section li a { text-decoration: none; position: relative; top: 0.55em; background: rgb(80%,85%,100%); display: block; }
此時會看到子選項內容 a 之間有 1px 的間隔,這是因為 a 的實際高度本來就比 li 少 1px 高 (li 比 a 多了線條的高度)。
增加距離避免重疊,就算完成了。
只要在分類間加一點距離,重疊的問題就解決了,為 .section 下方加上 padding 應是較恰當的方式。為了分類裡面的上下距離看起來一樣 ([上古神話]上方與[章回小說]下方) ,我們指定了 padding-bottom:1.1em; ,與行高相等的距離。
- 在前面已指定的
.section增加css定義 (紅字) -
.TreeMenu .section { line-height: 1.1; padding-bottom: 1.1em; }
換成在 ul 下方增加距離也可以,不過,只能以 margin 來定義,因為 padding 會使左側的線跟著向下延長,就不會與最後一個 li 的橫線緊接了。
目前應該已經算是完成囉,只剩下修飾更好而已。
hasLayout 處理 ie bugs
ie 7 或 ie 6 ,在 ul 或 a 可能會發生高度失準或背景圖片移位的問題,解決這類的 bugs 常用的方式是 hasLayout property 。由於目前在 ie 8 都還正常,為了清楚區隔,我們最好運用 css hacks 技巧。
- 視問題的區域,自行斟酌增加
css定義 -
*+html .TreeMenu .section ul { zoom:1; } /*hack ie7*/ * html .TreeMenu .section ul { zoom:1; } /*hack ie6*/ *+html .TreeMenu .section ul a { zoom:1; } /*hack ie7*/ * html .TreeMenu .section ul a { zoom:1; } /*hack ie6*/ - 如果
a還是有高度或不正常間隙問題 -
*+html .TreeMenu .section ul a { zoom:1; vertical-align:top; } /*hack ie7*/ * html .TreeMenu .section ul a { zoom:1; vertical-align:top; } /*hack ie6*/
在子選項前加小圖示,並且做最後修飾
以小圖示作為 a 的背景,並且指定左邊 padding 距離,讓 a 的內容文字向內縮排,才不會與小圖示重疊。例中的小球圖示 (ic008.png) 寬度 10px ,我們指定它的位置在 a 的最左側並且上下居中,這樣會讓小球剛好緊接在 li 的線後,然後左側 padding 距離為 15px ,讓字不要與圖看起來太緊鄰。另外,把 a 的背景顏色指定成與 .TreeMenu 相同。
我們也在 a 及標題 h1 上下加了一點 padding 距離,讓字看起來不會與邊緣太緊鄰。不過, a 上下各增加了 0.25em ,表示整行的高度也增加了,所以,向下位移的 top 定義也需要對等增加 0.25em 的距離 (0.55 + 0.25 = 0.8em) ;而 .section 下方的 padding 距離也應該增加為 1.6em (1.1em + 0.25em + 0.25em) 。
- 範例完整的
css設計 -
h1, ul { margin: 0; padding: 0; } .TreeMenu { width: 10em; background: rgb(92%,86%,100%); border: 1px solid rgb(60%,60%,80%); } .TreeMenu .section { line-height: 1.1; padding-bottom:1.6em; } .TreeMenu .section h1 { font-size: 100%; font-weight: normal; background: rgb(85%,70%,90%); padding-top: 0.25em; padding-bottom: 0.25em; } .TreeMenu .section ul { list-style: none; margin-left: 0.5em; border-left: 1px dotted; } *+html .TreeMenu .section ul { zoom:1; padding-bottom:1px; margin-bottom:-1px; } /*hack ie 7*/ * html .TreeMenu .section ul { zoom:1; padding-bottom:1px; margin-bottom:-1px; } /*hack ie 6*/ .TreeMenu .section li { padding-left: 0.5em; border-bottom: 1px dotted; } .TreeMenu .section li a { text-decoration: none; position: relative; top: 0.8em; background: rgb(92%,86%,100%) url(ic008.png) no-repeat left center; display: block; padding: 0.25em 4px 0.25em 15px; margin-bottom: -1px; } *+html .TreeMenu .section ul a { zoom:1; vertical-align:top; } /*hack ie 7*/ * html .TreeMenu .section ul a { zoom:1; vertical-align:top; } /*hack ie 6*/
前面提到由於 li 的下方線條使 a 之間會有 1px 間距,只需要在 a 或 li 指定 margin-bottom:-1px; (綠字),就會使 li 之間有 1px 重疊, a 之間就沒有間距了,不過, ie 7, ie 6 最後一個 li 的線會看不見,修正方式也加在 hacks 裡了 (綠字) ,有興趣可以自行試試。

感謝分享~~~對我這個css新手有相當大的幫助
我只能說,老師的部落格內容真是太有深度了。 好難喔~~ 讚!讚!讚!
太仔細了,感謝分享~~~
感謝板主 我在PIXNET討論區所問的問題 透過你的指點 問題解決了~