46

私はあなたの典型的なドロップダウンナビゲーションを持っています、そして私はドロップメニューリンクが常にアクセス可能で見えるようにしようとしています:

<li><a href="#">Link 1</a>
    <ul>
        <li><a href="#">Link 1</a></li>
        <li><a href="#">Link 2</a></li>
        <li><a href="#">Link 3</a></li>
    </ul>
</li>
<li><a href="#">Link 2</a>
    <ul>
        <li><a href="#">Link 1</a></li>
        <li><a href="#">Link 2</a></li>
        <li><a href="#">Link 3</a></li>
    </ul>
</li>
<!-- etc. -->
</ul>

CSSは実際には特別なものではありません(色と背景が削除されています):

.dropdown,
.dropdown li,
.dropdown ul {
    list-style:none;
    margin:0;
    padding:0;
}
.dropdown {
    position:relative;
    z-index:10000;
    float:left;
    width:100%;
}
.dropdown ul {
    position:absolute;
    top:100%;
    visibility:hidden;
    display:none;
    width:16em;
}
.dropdown ul ul {
    top:0;
    left:100%;
}
.dropdown li {
    position:relative;
    float:left;
}
.dropdown li:hover{
    z-index:910;
}
.dropdown ul:hover,
.dropdown li:hover > ul,
.dropdown a:hover + ul,
.dropdown a:focus + ul {
    visibility:visible;
    display:block;
}
.dropdown a {
    display:block;
    padding:1em 2em;
}
.dropdown ul li {
    width:100%;
}

不明な数のトップレベルリンクがあります(それらはユーザーによって作成されます)。私が抱えている問題は、トップレベルのリンクが右に遠すぎると、ドロップメニュー(右に行く)が画面から消えることがあるということです。これを補うためにCSSのこのビットを追加しました:

.dropdown > li:last-child ul { /* ...or use a class on the last link for IE */
    right:0;
}

これで、最後の1つが画面外ではなく左側に表示されます。これはすばらしいことですが、いくつかの問題があります。

  1. 最後のリンクは常に画面の端にあるとは限らないため(リンクが3つしかない場合など)、これらのスタイルが常に必要になるとは限りません。
  2. ブラウザウィンドウのサイズが変更されると、リンクは(設計上)互いに重なり合います。シーケンスの途中のリンクが右端になり、ドロップダウンが途切れる場合があります。
  3. 「最後から2番目」のリンクのメニューも境界の外に出ることがあります。

このデモのパネルのサイズを変更して、意味を確認します(赤い領域は「画面外」と見なされます) http://jsfiddle.net/G7qfq/

私はこの厄介な一般的な問題に何年も苦労してきましたが、満足のいく解決策を見つけることはできませんでした。ドロップメニューが画面から消えるかどうかを確認する方法はありますか?そうであれば、class名前などを追加/削除して、CSSで画面に表示したままにすることができますか?

私が使用するかもしれない1つの手がかりは、メニュー画面から消えた場合、ウィンドウの下部に常に垂直スクロールバーが表示されるということですが、その知識の使い方がわかりません。垂直スクロールバーの検出に関するこの質問に対する受け入れられた回答を試しましたが、何らかの理由で常に戻りtrue、常に「エッジ」クラスが追加されます(タイミングに問題がある可能性がありますか?):

$(".dropdown li").on('mouseenter mouseleave', function (e) {

    // Get the computed style of the body element
    var cStyle = document.body.currentStyle||window.getComputedStyle(document.body, "");

    // Check the overflow and overflowY properties for "auto" and "visible" values
    hasVScroll = cStyle.overflow == "visible" 
             || cStyle.overflowY == "visible"
             || (hasVScroll && cStyle.overflow == "auto")
             || (hasVScroll && cStyle.overflowY == "auto");

    if (hasVScroll) {
        $(this).addClass('edge');
    } else {
        $(this).removeClass('edge');
    }
});​

javascriptを使用したデモ:http://jsfiddle.net/G7qfq/2/

本当に、一瞬でも垂直スクロールバーを見たくないので、それが進むべき道かどうかはわかりません。さらに、誤検知(他の理由でスクロールバー)が発生する可能性があります。

私はまた、私が認めるこの回答の解決策を試しましたが、私は完全には理解しておらず、それを機能させることができませんでした:http: //jsfiddle.net/G7qfq/3/

$(".dropdown li").on('mouseenter mouseleave', function (e) {

    var elm = $('ul:first', this);
    var off = elm .offset();
    var t = off.top;
    var l = off.left;
    var h = elm.height();
    var w = elm.width();
    var docH = $(window).height();
    var docW = $(window).width();

    var isEntirelyVisible = (t > 0 && l > 0 && t + h < docH && l+ w < docW);

    if ( ! isEntirelyVisible ) {
        $(this).addClass('edge');
    } else {
        $(this).removeClass('edge');
    }
});​

ソリューションにはjavascriptが必要であり、jQueryを使用していると思いますが、問題に対処する方法がわかりません。何か案は?

4

3 に答える 3

63

私はあなたがほとんどそこにいたと思います...

あなたは本当に幅に関係する計算だけに興味があるべきです。ドロップダウン要素の幅とその要素のオフセットがコンテナの幅よりも大きい場合は、メニューを切り替えます。

$(function () {
    $(".dropdown li").on('mouseenter mouseleave', function (e) {
        if ($('ul', this).length) {
            var elm = $('ul:first', this);
            var off = elm.offset();
            var l = off.left;
            var w = elm.width();
            var docH = $(".container").height();
            var docW = $(".container").width();

            var isEntirelyVisible = (l + w <= docW);

            if (!isEntirelyVisible) {
                $(this).addClass('edge');
            } else {
                $(this).removeClass('edge');
            }
        }
    });
});

http://jsfiddle.net/G7qfq/582/

于 2012-07-17T14:50:47.283 に答える
3

右または下にフライアウトするメニューに使用できる関数は次のとおりです(@ r0m4nのコードに基づく):

function fixFlyout (containerElement, parentElement,flyoutElement,flyoutDirection) {
    $(parentElement).on('mouseenter mouseleave', function (e) {
        var element = $(flyoutElement, this);
        var offset = element .offset();
        switch(flyoutDirection) {
            case 'down':
                var top = offset.top;
                var height = element.height();
                var windowHeight = $(containerElement).height();
                var isEntirelyVisible = (top + height <= windowHeight);
                break;
            case 'right':
                var left = offset.left;
                var width = element.width();
                var windowWidth = $(containerElement).width();
                var isEntirelyVisible = (left + width <= windowWidth);
                break;
        }
        if (!isEntirelyVisible ) {
            $(element).addClass('edge');
        } else {
            $(element).removeClass('edge');
        }
    });
}
//Level 1 Flyout
fixFlyout(containerElement = '.header',parentElement = '.header .navigation>.menu>.expanded',flyoutElement = '.menu:first',flyoutDirection = 'down');
于 2015-06-26T13:28:03.190 に答える
0

addClass('edge')を正しく機能させることはできませんでしたが、動作を実現するために問題の要素のCSSを変更することはできました。(r0m4nからわずかに変更されただけ):

        //Align submenu to right if cut-off from window
        $(function () {
            $(".dropdown").on('mouseenter mouseleave', function (e) {
                if ($('.dropdown-content', this).length) {
                    var dropdownElement = $('.dropdown-content:first', this);
                    var elementOffset = dropdownElement.offset();
                    var elementOffsetLeft = elementOffset.left;
                    var elementWidth = dropdownElement.width();
                    var pageHeigth = $(".show-on-scroll-wrapper").height();
                    var pageWidth = $(".show-on-scroll-wrapper").width();
                    //if left offset + width of dropdown is bigger than container width then it is cut-off
                    if ((elementOffsetLeft + elementWidth) > pageWidth) {
                        //Align Right
                        $(".dropdown-content").css({ "left":"auto", "right":"0", "margin-right":"-10px;"});
                    } else {
                        //Align Left
                        $(".dropdown-content").css({ "left":"0", "right":"auto", "margin-left": "-10px;" });
                    }
                }
            });
        });
于 2018-08-16T01:33:34.687 に答える