1. 程式人生 > >網頁導航菜單的子菜單平鋪(帶背景欄)實現

網頁導航菜單的子菜單平鋪(帶背景欄)實現

body hover 動態設置 ive 要求 解決方案 滿了 gpo 位置

-

之前給公司做的一個小型知識庫管理網站時遇到一個問題,在這裏記錄下解決的過程。

公司的美工要求首頁導航菜單 要跟他們公司的網站風格保持一致,如圖所示

技術分享圖片

(子菜單是平鋪的)

技術分享圖片

我一看,心想很簡單嘛

先貼一下通用菜單html結構

<li>
<a href="" class="abc">熱設計</a>
<ul>
<li><a href="">設計規範</a></li>
<li><a href="">案例分享</a></li>
<li><a href="">經驗文章</a></li>

</ul>

</li>

只要設置子菜單的<li>css為float:left,並給<ul>設置背景就可以了嘛

但是 實現的時候發現並不簡單,因為<ul>的位置是基於一級菜單<li>的位置的,所以<ul>的背景欄只會從一級菜單的<li>的位置開始顯示,不會顯示通欄(背景欄會鋪滿頁面)

於是我想給子菜單的<ul>外面包一層<div>,並設置<div> position:absolute; left:0; top:0;並取消一級菜單<li>的position:relative屬性

最終得到這樣的結果

技術分享圖片

技術分享圖片

雖然背景欄鋪滿了,但是子菜單卻不跟一級菜單對齊了。

通常是設置以及菜單的<li>為position:relative;而子菜單的<ul>(或本例中外層的div)為position:absolute,(偏移多少可以自行設置left跟top)這樣就可以使子菜單隨父菜單對齊了,

但是為了設置通欄的背景,去掉了一級菜單<li>的position:relative屬性,導致子菜單無法跟蹤父菜單;

於是設想 仍設置一級菜單<li>為position:relative,而設置div為position:fixed(position為fixed時只會根據整個屏幕進行布局,並始終懸浮,父容器的position是否為relative並不影響)

同時設置子菜單的<ul>為position:absolute,意圖是想讓子菜單<ul>跨過其父容器<div>,而去跟蹤祖容器(即一級菜單的<li>)位置(因為了解到容器的position設置為absolute時,會去查找它父容器是否設置了position為relative,若設置了則根據其位置進行定位,若未設置就繼續往上層祖容器查找,若都未設置,則根據頁面進行定位)

結果如圖:

技術分享圖片

技術分享圖片

子菜單全部移動到最左側了(因為設置了left:0),說明子菜單沒有追蹤一級菜單的<li>,而是跟隨了其父容器<div>的位置,就是說父容器只要設置了position屬性,不管是否為relative,子容器都會根據其位置進行定位。

這樣從邏輯上確定了只靠css是無法實現需要的效果的

{

1 要想設置背景為通欄,只能設置div為positon:absolute;left:0;且不能設置一級菜單<li>的position屬性;

2 要想讓子菜單追蹤父菜單的位置,必須設置父菜單的position:relative,同時設置子菜單position:absolute;

1與2互相矛盾

}

所以 我們只能另尋他法,即jquery

jquery有一個名為 offset() 的方法,可以獲取某個元素的位置(若該元素是基於父元素的位置定位的,在該方法獲得相對於父元素的位置,不然則是相對於整個屏幕的位置)

如元素p, var pos=p.offset(), pos具有兩個屬性:p.top , p.left,根據字面意思就可以了解其含義;同時offset(top:x;top:y)可以動態設置元素的位置

我們在菜單的hover事件中對子菜單進行定位,代碼如下所示

  var _this1 = null;
            $(.nav>li).hover(function () {
                _this1 = $(this);
                _this1.find(.second-nav).show();
                var p = _this1.offset();
                _this1.find(.second-nav).find(ul).offset({top:p.top+50,left:p.left-50})
                _this1.find(.abc).css(color,  #ff6a00)
                var _this2 = null;
                _this1.find(.second-nav).find(li).hover(function () {
                    _this2 = $(this);
                    _this2.find(.third-nav).show();
                    _this2.find(.third-nav).hover(function () {
                        $(this).show();
                    }, function () {
                        $(this).hide();
                    });
                }, function () {
                    _this2.find(.third-nav).hide();
                });
            }, function () {
                _this1.find(.second-nav).hide();
                _this1.find(.abc).css(color,  #fff)

            });

其中加粗斜體為新加的兩行代碼(其他的代碼都是導航菜單原有的),其中_this變量為鼠標滑過的一級菜單標題的<li>,

_this.offset()取得當前激活標題相對於屏幕的位置,並存入變量p,然後

_this1.find(‘.second-nav‘).find(‘ul‘).offset({top:p.top+50,left:p.left-50})

然後根據_this找到子代元素<ul>應用offset(top:x,left:y)方法進行定位,最後得到需要的結果

技術分享圖片

技術分享圖片

現在來看,這實在不算什麽問題,解決方案也很簡單,如果對jquery了解夠多的話

當然,這都是後話了,當時還是糾結了好久,心路歷程很曲折哈哈。

還是要把基礎學紮實。

網頁導航菜單的子菜單平鋪(帶背景欄)實現