网页导航菜单的子菜单平铺(带背景栏)实现
-
之前给公司做的一个小型知识库管理网站时遇到一个问题,在这里记录下解决的过程。
公司的美工要求首页导航菜单 要跟他们公司的网站风格保持一致,如图所示
(子菜单是平铺的)
我一看,心想很简单嘛
先贴一下通用菜单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了解够多的话
当然,这都是后话了,当时还是纠结了好久,心路历程很曲折哈哈。
还是要把基础学扎实。