Подтвердить что ты не робот

Обнаружить, если выпадающая навигация исчезнет с экрана и изменит его положение

У меня есть типичная выпадающая навигация, и я стараюсь, чтобы ссылки меню перетаскивания всегда были доступны и видимы:

<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;
}

Теперь последний идет влево вместо экрана, что приятно, но есть несколько проблем:

  • Мне не нужны эти стили для последней ссылки, так как она не всегда находится на краю экрана (например, если есть только 3 ссылки).
  • Когда окно браузера изменяется, ссылки стекаются друг над другом (по дизайну). Иногда ссылки в середине последовательности заканчиваются на правом краю, а их выпадающие окна обрезаются.
  • Иногда меню ссылок "рядом с последним" также выходит за пределы границы.

Измените размер панели в этой демонстрации, чтобы увидеть, что я имею в виду (красная область считается "вне экрана" ) http://jsfiddle.net/G7qfq/

Я боролся с этой досадной проблемой в течение многих лет и никогда не нашел удовлетворительного решения. Есть ли способ проверить, не исчезнет ли меню выпадающего меню, и если да, добавьте/удалите имя class или что-то еще, чтобы я мог сохранить его на экране с помощью CSS?

Один ключ, который я могу использовать, состоит в том, что если меню выходит из экрана, оно всегда создает вертикальную полосу прокрутки в нижней части окна, но я не уверен, как использовать эти знания. Я пробовал принятый ответ на этот вопрос об обнаружении вертикальных полос прокрутки, но по какой-то причине он всегда возвращает true и всегда добавляет класс "edge" (возможно, там проблема со временем?):

$(".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, но у меня нет подсказки, как подойти к проблеме. Любые идеи?

4b9b3361

Ответ 1

Я думаю, вы были почти там...

Вас действительно интересуют только вычисления, связанные с шириной. Если ширина выпадающего элемента и смещение этого элемента больше ширины контейнера, вы хотите переключить свое меню.

$(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/

Ответ 2

Вот функция, которая может использоваться для меню, которое вылетает вправо или вниз (на основе кода @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 = (top + 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');