Очередной блог фрилансера

коротко и полезно о веб-разработке

Menu Close

Решение для очень длинных выпадающих меню

Мне нравится давать статьям точные заголовки, но в данном случае, правильно было бы сказать *возможное* решение для очень длинного, выпадающего меню. Проблема с такими меню состоит в том, что выпадающий список может выйти за пределы самой веб-страницы, то есть ниже видимой области окна браузера. Так, что для доступа к нижним пунктам меню, вам понадобится прокручивать страницу до нужного пункта.

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

Но есть очень простое решение для этого. Прежде чем мы начнем, взгляните на результат.

Впервые, я увидел эту идею на странице аккаунта, на сайте Media Temple. У них есть выпадающее меню для «Доменов», в котором перечислены все ваши домены, находящиеся у них на хостинге. Это может быть очень длинный список. Но, Media Temple применили специальную технику – при прокручивании окна, меню также прокручивается в ускоренном режиме.

mt-below-fold

И конечно, поскольку я делал скриншот, то обратил внимание, что замечательное решение, которое они так расхваливали, оказалось не таким уж хорошим. Это заставило меня задуматься, какие именно проблемы у них возникают с этим меню, так что давайте смотреть вместе. Далее представлена визуализация идеи:

visual-long-dropdowns

JQuery делает это мгновенно

Я выложу весь код здесь, просто для справки. Код сопровождают комментарии, так что понять его будет легко. Он насчитывает 60 строк, но не пугайтесь, что это слишком много, весь код очень простой.

  1. Устанавливаем максимальную высоту выпадающего меню
  2. При наведении открываем дочернее меню
  3. Рассчитываем коэффициент скорости, основанный на высоте дочернего меню
  4. Отслеживаем движение мыши в меню
  5. Прокручиваем меню вместе с движением мыши, основываясь на коэффициенте
  6. При покидании мыши, закрываем меню
var maxHeight = 400;

$(function(){

    $(".dropdown > li").hover(function() {

         var $container = $(this),
             $list = $container.find("ul"),
             $anchor = $container.find("a"),
             height = $list.height() * 1.1,     // проверяем, достаточно ли свободного места внизу
             multiplier = height / maxHeight; // необходим для более быстрого движения, если список длиннее

        // сохраняем высоту здесь, так что она восстанавливается при покидании мыши       
$container.data("origHeight", $container.height());

        // сохраняем цвет наведения, пока открыто выпадающее меню
        $anchor.addClass("hover");

        // проверяем, появился ли список непорседственно под родительским списком
        $list
            .show()
            .css({
                paddingTop: $container.data("origHeight")
            });

        // Не применяем анимацию, если список короче максимального
        if (multiplier > 1) {
            $container
                .css({
                    height: maxHeight,
                    overflow: "hidden"
                })
                .mousemove(function(e) {
                    var offset = $container.offset();
                    var relativeY = ((e.pageY - offset.top) * multiplier) - ($container.data("origHeight") * multiplier);
                    if (relativeY > $container.data("origHeight")) {
                        $list.css("top", -relativeY + $container.data("origHeight"));
                    };
                });
        }

    }, function() {

        var $el = $(this);

        // возвращаем все как было
        $el
            .height($(this).data("origHeight"))
            .find("ul")
            .css({ top: 0 })
            .hide()
            .end()
            .find("a")
            .removeClass("hover");

    });

    // Добавляем нижнюю стрелку только для тех пунктов, у которых есть дочернее меню
    $(".dropdown > li:has('ul')").each(function() {
        $(this).find("a:first").append("<img src='images/down-arrow.png' />");
    });

});

HTML и CSS

Я не стал выкладывать здесь HTML и CSS, поскольку они очень простые и не интересные. Вы, в любом случае, можете скачать архив с примером, и посмотреть. Это самый обыкновенный, вложенный, маркированный список, и немного очень простых стилей.

Тестирование

Пример тестировался во всех браузерах, вплоть до IE6, меню отлично выглядит и работает везде.

Скачать архив с примером.

Перевод статьи «Solution For Very Long Dropdown Menus«, автор Chris Coyier

Рассказать друзьям

Понравилась статья? Лучший способ сказать спасибо - поделиться ссылкой в социальных сетях: