Bootstrap nav 子菜单根据页面限制向左或向右浮动
Posted
技术标签:
【中文标题】Bootstrap nav 子菜单根据页面限制向左或向右浮动【英文标题】:Bootstrap nav submenu float left or right according to page limits 【发布时间】:2017-07-16 08:29:27 【问题描述】:我在一个基于 Bootstrap 和 jQuery 的项目中有一个多级菜单。 一切正常,除了一件事:当一个菜单项放在右边太多时,它的子菜单超出了页面并且不可读(如从 jsFiddle 截取的屏幕截图所示):
有没有办法检测子菜单(打开时)是否超过页面限制,如果超过,是否放置在其父元素的另一侧?
到目前为止我的代码是:
html:
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">LOGO HERE!</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li><a href="/">Home</a></li>
<li><a href="#">About Us</a></li>
<li><a href="#">Services</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Blog <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Categories</a></li>
<li><a href="#">Blog Post</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown dropdown-submenu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Search Engines</a>
<ul class="dropdown-menu">
<li class="dropdown dropdown-submenu"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Google</a>
<ul class="dropdown-menu">
<li><a href="https://adwords.google.com" target="_blank">Google Adwords</a></li>
<li><a href="https://analytics.google.com" target="_blank">Google Analytics</a></li>
<li><a href="https://www.google.com/webmaster/" target="_blank">Webmaster Tools</a></li>
</ul>
</li>
<li><a href="http://www.yahoo.com">Yahoo</a></li>
<li><a href="http://www.msn.com">MSN</a></li>
</ul>
</li>
<li role="separator" class="divider"></li>
<li><a href="#">All Tags</a></li>
</ul>
</li>
<li><a href="#">News</a></li>
<li><a href="#">Contact</a></li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container -->
</nav>
CSS:
.dropdown-menu>li>a:hover
background-color:rgba(216,216,216,1);
background-image:none;
color:#000;
.divider
background-color:#fff;
.dropdown-submenu
position:relative;
.dropdown-submenu>.dropdown-menu
top:0;
left:100%;
margin-top:-6px;
margin-left:-1px;
-webkit-border-radius:0 6px 6px 6px;
-moz-border-radius:0 6px 6px 6px;
border-radius:0 6px 6px 6px;
.dropdown-submenu>a:after
display:block;
content: " ";
float:right;
width:0;
height:0;
border-color:transparent;
border-style: solid;
border-width:5px 0 5px 5px;
border-left-color: #cccccc;
margin-top:5px;
margin-right: -10px;
.dropdown-submenu:hover>a:after
border-left-color: #555;
.dropdown-submenu.pull-left
float:none;
.dropdown-submenu.pull-left>.dropdown-menu
left:100%;
margin-left:1-0px;
-webkit-border-radius:6px 0 6px 6px;
-moz-border-radius:6px 0 6px 6px;
border-radius:6px 0 6px 6px;
JS:
$(document).ready(function()
$('a[data-toggle=dropdown]').on('click', function(e)
//$(this).next('ul').show();
//console.log('click');
e.stopPropagation();
e.preventDefault();
$(this).parent().siblings().removeClass('open');
$(this).parent().toggleClass('open');
);
if($('.dropdown-menu').hasClass('open'))
console.log('visible');
);
在这里测试小提琴:https://jsfiddle.net/311mcf23/
任何帮助将不胜感激。
【问题讨论】:
【参考方案1】:经过一番研究,我偶然发现了这个话题:How to check if an element is off-screen
按照@Sam Sehnert 的建议,我最终使用了可以在此处找到的插件:https://github.com/customd/jquery-visible
经过一些小的修改,结果正是我想要的!
HTML:
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">LOGO HERE!</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li><a href="/">Home</a></li>
<li><a href="#">About Us</a></li>
<li><a href="#">Services</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">Blog <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Categories</a></li>
<li><a href="#">Blog Post</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown dropdown-submenu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
aria-haspopup="true" aria-expanded="false">Search Engines</a>
<ul class="dropdown-menu">
<li class="dropdown dropdown-submenu"><a href="#" class="dropdown-toggle"
data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">Google</a>
<ul class="dropdown-menu">
<li><a href="https://adwords.google.com" target="_blank">Google Adwords</a></li>
<li><a href="https://analytics.google.com" target="_blank">Google Analytics</a>
</li>
<li><a href="https://www.google.com/webmaster/" target="_blank">Webmaster
Tools</a></li>
</ul>
</li>
<li><a href="http://www.yahoo.com">Yahoo</a></li>
<li><a href="http://www.msn.com">MSN</a></li>
</ul>
</li>
<li role="separator" class="divider"></li>
<li><a href="#">All Tags</a></li>
</ul>
</li>
<li><a href="#">News</a></li>
<li><a href="#">Contact</a></li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container -->
CSS:
.dropdown-menu>li>a:hover
background-color:rgba(216,216,216,1);
background-image:none;
color:#000;
.divider
background-color:#fff;
.dropdown-submenu
position:relative;
.dropdown-submenu>.dropdown-menu
top:0;
left:100%;
margin-top:-6px;
margin-left:-1px;
-webkit-border-radius:0 6px 6px 6px;
-moz-border-radius:0 6px 6px 6px;
border-radius:0 6px 6px 6px;
.dropdown-submenu>a:after
display:block;
content: " ";
float:right;
width:0;
height:0;
border-color:transparent;
border-style: solid;
border-width:5px 0 5px 5px;
border-left-color: #cccccc;
margin-top:5px;
margin-right: -10px;
.dropdown-submenu:hover>a:after
border-left-color: #555;
.dropdown-submenu.pull-left
float:none;
.dropdown-submenu.pull-left>.dropdown-menu
left:100%;
margin-left:1-0px;
-webkit-border-radius:6px 0 6px 6px;
-moz-border-radius:6px 0 6px 6px;
border-radius:6px 0 6px 6px;
.rev
left:auto !important;
right:100% !important;
top:8px !important;
margin-right:-12px !important;
JS:
(function ($)
/**
* Copyright 2012, Digital Fusion
* Licensed under the MIT license.
* http://teamdf.com/jquery-plugins/license/
*
* @author Sam Sehnert
* @desc A small plugin that checks whether elements are within
* the user visible viewport of a web browser.
* only accounts for vertical position, not horizontal.
*/
$.fn.visible = function (partial, hidden, direction, container)
if (this.length < 1) return;
var $t = this.length > 1 ? this.eq(0) : this,
isContained = typeof container !== "undefined" && container !== null,
$w = isContained ? $(container) : $(window),
wPosition = isContained ? $w.position() : 0,
t = $t.get(0),
vpWidth = $w.outerWidth(),
vpHeight = $w.outerHeight(),
direction = direction ? direction : "both",
clientSize = hidden === true ? t.offsetWidth * t.offsetHeight : true;
if (typeof t.getBoundingClientRect === "function")
// Use this native browser method, if available.
var rec = t.getBoundingClientRect(),
tViz = isContained
? rec.top - wPosition.top >= 0 && rec.top < vpHeight + wPosition.top
: rec.top >= 0 && rec.top < vpHeight,
bViz = isContained
? rec.bottom - wPosition.top > 0 &&
rec.bottom <= vpHeight + wPosition.top
: rec.bottom > 0 && rec.bottom <= vpHeight,
lViz = isContained
? rec.left - wPosition.left >= 0 &&
rec.left < vpWidth + wPosition.left
: rec.left >= 0 && rec.left < vpWidth,
rViz = isContained
? rec.right - wPosition.left > 0 &&
rec.right < vpWidth + wPosition.left
: rec.right > 0 && rec.right <= vpWidth,
vVisible = partial ? tViz || bViz : tViz && bViz,
hVisible = partial ? lViz || rViz : lViz && rViz;
if (direction === "both") return clientSize && vVisible && hVisible;
else if (direction === "vertical") return clientSize && vVisible;
else if (direction === "horizontal") return clientSize && hVisible;
else
var viewTop = isContained ? 0 : wPosition,
viewBottom = viewTop + vpHeight,
viewLeft = $w.scrollLeft(),
viewRight = viewLeft + vpWidth,
position = $t.position(),
_top = position.top,
_bottom = _top + $t.height(),
_left = position.left,
_right = _left + $t.width(),
compareTop = partial === true ? _bottom : _top,
compareBottom = partial === true ? _top : _bottom,
compareLeft = partial === true ? _right : _left,
compareRight = partial === true ? _left : _right;
if (direction === "both")
return (
!!clientSize &&
compareBottom <= viewBottom &&
compareTop >= viewTop &&
compareRight <= viewRight &&
compareLeft >= viewLeft
);
else if (direction === "vertical")
return (
!!clientSize && compareBottom <= viewBottom && compareTop >= viewTop
);
else if (direction === "horizontal")
return (
!!clientSize && compareRight <= viewRight && compareLeft >= viewLeft
);
;
)(jQuery);
$(document).ready(function ()
$("a[data-toggle=dropdown]").on("click", function (e)
e.stopPropagation();
e.preventDefault();
$(this).parent().siblings().removeClass("open");
$(this).parent().toggleClass("open");
if ($(window).width() > 767)
if ($(this).parent("li").hasClass("open"))
if (!$(this).next("ul").visible())
console.log("not visible");
$(this).next("ul").addClass("rev");
else
$(this).next("ul").removeClass("rev");
);
);
结果可见这里:https://jsfiddle.net/captain_theo/311mcf23/2/
希望能帮助其他有类似问题的人。
西奥
【讨论】:
【参考方案2】:尝试从 css 中删除此代码
.dropdown-submenu>.dropdown-menu
top:0;
left:100%;
margin-top:-6px;
margin-left:-1px;
-webkit-border-radius:0 6px 6px 6px;
-moz-border-radius:0 6px 6px 6px;
border-radius:0 6px 6px 6px;
【讨论】:
我试过了,但是子菜单正好落在父元素的正下方 - 这不好,因为这可能会让用户感到困惑【参考方案3】:当与视口发生碰撞时不容易检测到。我建议像这样向左移动子菜单..
.dropdown-submenu>.dropdown-menutop:0;left:-99%;max-width:180px;margin-top:-6px;margin-right:-1px;-webkit-border-radius:6px 6px 6px 6px;-moz-border-radius:6px 6px 6px 6px;border-radius:6px 6px 6px 6px;
.dropdown-submenu:hover>.dropdown-menudisplay:block;
.dropdown-submenu>a:afterdisplay:block;content:" ";float:left;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 5px 5px 0;border-right-color:#999;margin-top:5px;margin-right:10px;
.dropdown-submenu.pull-left>.dropdown-menuleft:-100%;margin-left:0px;-webkit-border-radius:6px 6px 6px 6px;-moz-border-radius:6px 6px 6px 6px;border-radius:6px 6px 6px 6px;
.dropdown-menu-right margin-left:0;
http://www.bootply.com/pho42x2it2
【讨论】:
嗯,这只是出于设计目的,我试图避免这种情况......毕竟对于我们这些习惯于从左到右阅读的人来说,这种建议的对齐方式可能有点尴尬...这就是为什么我只想在给定元素超出视口时这样做。以上是关于Bootstrap nav 子菜单根据页面限制向左或向右浮动的主要内容,如果未能解决你的问题,请参考以下文章
wp_nav_menu walker 类子菜单仅显示在父页面上
Wordpress 3.5 - 如何仅使用 wp_nav_menu 显示父级的子菜单?
使用带有 react-bootstrap 的 Nav 组件的 Accordion SideBar 菜单
php Wordpress菜单/导航----将.active类添加到活动菜单项---- Bootstrap Nav Walker