原文地址,排版效果更好css
https://blog.codelabo.cn/article/5ce4f0eb8aab210ff34d0150html
https://xboxyan.codelabo.cn/post/css-tree-padding/前端
在平時的項目中會常常碰到這樣一種佈局,暫且稱之爲多級菜單吧wordpress
(截圖來自於ant-design)佈局
這類佈局也很容易,大概就是這樣ul
和li
嵌套,以下post
<ul class="parent"> <li> <div>Navigation01</div> <ul> <li><div>Option01</div></li> <li><div>Option02</div></li> <li> <div>Submenu</div> <ul> <li><div>Option03</div></li> <li><div>Option04</div></li> </ul> </li> </ul> </li> <li><div>Navigation02</div></li> </ul>
因而就獲得下面一個很原始的樣式。學習
再通過簡單的修飾就能夠達到上面的效果了。優化
固然,這個很容易,通常狀況下咱們是經過設置內邊距來完成的,好比默認爲spa
ul{ padding-left:40px; }
而後每一層級跟隨父級逐步累積,而後就實現了,層級越深,距離左邊的縮進越多的效果。設計
經過上面的佈局和樣式,很顯然每一項的選擇範圍都是逐步縮進的,
可是,可能設計師以爲很差看,每每會設計成通欄的形式,好比像上面ant-design的設計
那麼,該如何處理呢?
首先,一個很天然的思路就是去除ul
的padding
,改成每個子項分別指定padding
ul.parent{ padding: 0; }
而後將內邊距直接寫在html
上,以下
<ul class="parent"> <li> <div style="padding-left:40px">Navigation01</div> <ul> <li><div style="padding-left:80px">Option01</div></li> <li><div style="padding-left:80px">Option02</div></li> <li> <div style="padding-left:80px">Submenu</div> <ul> <li><div style="padding-left:120px">Option03</div></li> <li><div style="padding-left:120px">Option04</div></li> </ul> </li> </ul> </li> <li><div style="padding-left:40px">Navigation02</div></li> </ul>
若是菜單層級較多,咱們一般使用js來輔助生成,注意每一次循環來指定不一樣的內邊距就能夠了
ant-design也是採起這種方式,能夠自行打開控制檯去查看。
記得剛入前端的時候就是採起的這種方式,效果實現就好。
不過,在如今看來,在html
中使用內聯樣式始終不雅,並且數量較多時還須要和js
扯上關係,可否優化一下呢
下面列舉兩種css方式
咱們能夠在上面的基礎上,分別控制每一級的內邊距,這裏咱們可使用子選擇器>
ul.parent>li>div{/**第一級**/ padding-left: 40px; } ul.parent>li>ul>li>div{/**第二級**/ padding-left: 80px; } ul.parent>li>ul>li>ul>li>div{/**第三級**/ padding-left: 120px; } /** ... **/
一般,在層級不是特別多的狀況下,咱們能夠一一羅列出來,只需用選擇器ul>li
疊加便可,是否是比style
方便維護了不少呢?
在講這個方法以前,首先搞清楚一個問題
absolute
在不設置方向屬性left
,top
,right
,bottom
時,默認位置是哪裏?
在個人學習過程當中,不少地方講到的都是說absolute
是絕對定位,是相對於第一個有定位屬性的父級的,因此基本上都是和relative
一塊兒使用,反正無論三七二十一,直接就給父級加上position:relative
,有一個可靠的父級,看着比較靠譜,不是嗎?
其實,當元素設置了absolute
屬性,沒有方向屬性時,元素仍保留在原來位置,只是不佔空間而已
好比,我給上面每一項後面加一個角標
ul.parent div:after{ content:'new'; font-size: 10px; position:absolute; margin-top: -5px; color: red }
能夠看到,雖然設置了absolute
屬性,但元素仍保留在原來位置,一旦設置了left
等方位屬性,就會查找第一個有定位屬性的父級。
如今,咱們把css
還原爲默認的狀態,也就是
ul{ padding-left:40px; }
如今狀況就和初始狀態一致,選中範圍逐層遞減,那麼,如何實現選中範圍爲通欄呢
咱們能夠給最外層父級設置position:relative
,由於通欄的寬度是相對於最外層的,而後給選中元素設置
ul.parent div:hover:before{ content:''; position:absolute; left:0; right:0; height:21px; background: violet; z-index: -1; }
這裏只設置了水平方向的left
和right
,沒有設置垂直方向上的屬性,因此水平位置會跟隨父級定位元素(這裏是最外層),而垂直方向位置仍是基於當前父級(這裏是父級li元素)
注意,這裏的高度因爲是基於最外層元素,因此,這裏不能設置height:100%
,那麼,如何解決這一個小瑕疵呢,畢竟在這裏寫一個固定高度實在不怎麼合適。
這裏有兩種方式來優化。
上面的方式若是不指定高度,因爲沒有內容,高度天然爲0,解決方式也很簡單,在content
插入一個空字符或者透明字符便可
ul.parent div:hover:before{ content:'\A0'; }
或者
ul.parent div:hover:before{ content:'任意字符'; color:transparent; }
一般子項目的高度都是固定的,能夠給子項目手動指定一個高度,而後選中項繼承該高度便可
ul.parent div{ height:24px; line-height:24px; } ul.parent div:hover:before{ content:''; height:inherit }
注意這裏的height:inherit
是繼承直接父級的高度,有興趣的能夠看張鑫旭的這篇文章
這樣也實現了通欄的效果
https://codepen.io/xboxyan/pe...
上面介紹了兩種實現通欄的方法,相比而言,absolute
效果更好,也易於維護,可能一個並不怎麼起眼的屬性,有時候也能發揮出意想不到的效果。
下面有一個案例,純css實現,能夠查看一下