【问题标题】:Bootstrap nav submenu float left or right according to page limitsBootstrap nav 子菜单根据页面限制向左或向右浮动
【发布时间】: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/

任何帮助将不胜感激。

【问题讨论】:

    标签: jquery css twitter-bootstrap drop-down-menu


    【解决方案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-menu{top: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-menu{display:block;}
      .dropdown-submenu>a:after{display: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-menu{left:-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

      【讨论】:

      • 嗯,这只是出于设计目的,我试图避免这种情况......毕竟对于我们这些习惯于从左到右阅读的人来说,这种建议的对齐方式可能有点尴尬...这就是为什么我只想在给定元素超出视口时这样做。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多