DataLife Engine > Версия для печати > Простой эффект меню, применяющийся на YouTube

Сегодня мы хотим рассказать вам о том, как можно воссоздать значительный эффект для меню, который вы уже наверняка встречали в левом боковом меню YouTube при просмотре видео (спрятанное под словом «Гид»). Меню состоит из небольшой иконки, ярлыка, и списка пунктов меню, которые появляются только после клика по иконке или ярлыку. После клика, иконка съезжает вправо, и ярлык перемещается вверх, позволяя отобразить пункты меню. Мы добавим еще кое-какие стили и эффекты, чтобы наше меню получилось немного более интересным.Давайте приступим!

Разметка

Что касается HTML, то здесь мы воспользуемся элементом nav, внутрь которого добавим div, содержащий иконку и ярлык нашего меню. Для расположения пунктов меню мы используем ненумерованный список:


    Account
    

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

Теперь давайте перейдем к CSS.

CSS-код

Обратите внимание на то, что CSS будет без браузерных префиксов, но в исходный файлах вы их сможете найти.

Для начала нам нужно включить наш иконический шрифт:

@font-face {
    font-family: 'icomoon';
    src:url('../fonts/icomoon.eot');
    src:url('../fonts/icomoon.eot?#iefix') format('embedded-opentype'),
        url('../fonts/icomoon.woff') format('woff'),
        url('../fonts/icomoon.ttf') format('truetype'),
        url('../fonts/icomoon.svg#icomoon') format('svg');
    font-weight: normal;
    font-style: normal;
}

Основной контейнер nav будет обозначен базовыми стилями – размером шрифта, высотой строки, цветом и габаритами. Нам нужно, чтобы он был гибким, но он не должен при этом становиться слишком большим или слишком маленьким, поэтому мы укажем еще и параметры max-width и min-width:

.dr-menu {
    width: 100%;
    max-width: 400px;
    min-width: 300px;
    position: relative;
    font-size: 1.3em;
    line-height: 2.5;
    font-weight: 400;
    color: #fff;
    padding-top: 2em;
}

Разделение, которое будет содержать span-элемент с иконкой меню и ссылку, будет позиционировано абсолютно, а курсор мы выставим на значение pointer. Здесь нам также нужно указать параметр z-index, который гарантировал бы нам то, что ненумерованный список не будет торчать поверх всего остального:

.dr-menu > div  {
    cursor: pointer;
    position: absolute;
    width: 100%;
    z-index: 100;
}

Span-элемент иконки меню в нашем разделении trigger, также будет позиционирован абсолютно, и мы создадим здесь небольшой переход:

.dr-menu > div .dr-icon {
    top: 0;
    left: 0;
    position: absolute;
    font-size: 150%;
    line-height: 1.6;
    padding: 0 10px;
    transition: all 0.4s ease;
}

Когда мы кликаем по разделению trigger, элементу nav будет задан класс dr-menu-open. Иконка меню затем отъедет влево, а мы также сдвинем ее на расстояние собственной ширины, чтобы затем она могла вернуться обратно без преломлений:

.dr-menu.dr-menu-open > div .dr-icon {
    color: #60a773;
    left: 100%;
    transform: translateX(-100%);
}

В конце нашего CSS-кода мы добавим к нашей иконке классы от IcoMoon. Иконка в span-элементе для иконки нашего меню будет немного отличаться, и мы воспользуемся псевдо-классом :after, чтобы добавить небольшой треугольник. Итак, давайте определим его следующим образом:

.dr-menu > div .dr-icon:after {
    content: "e008";
    position: absolute;
    font-size: 50%;
    line-height: 3.25;
    left: -10%;
    opacity: 0;
}

Иконка будет позиционирована абсолютно, и мы расположим ее как надо, задав параметр left со значением -10%. Исходный уровень непрозрачности будет выставлен на 0, так как нам не нужно видеть ее, когда меню закрыто.Как только открывается меню, иконка становится видимой:

.dr-menu.dr-menu-open > div .dr-icon:after {
    opacity: 1;
}

Ярлык, который является анкором в нашем HTML, также получит некоторые базовые стили, и мы также зададим ему отступы, чтобы расположить его сразу рядом с иконкой меню. Мы также добавим переход, так как нам нужно анимировать ее, как только меню будет открыто. И сделаем мы это, переместив ее по оси Y:

.dr-menu > div .dr-label {
    padding-left: 3em;
    position: relative;
    display: block;
    color: #60a773;
    font-size: 0.9em;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    line-height: 2.75;
    transition: all 0.2s ease-in;
}

.dr-menu.dr-menu-open > div .dr-label {
    transform: translateY(-90%);
}

Ненумерованный список изначально будет невидим, так как мы зададим ему параметр непрозрачности со значением 0:

.dr-menu ul {
    padding: 0;
    margin: 0 3em 0 0;
    list-style: none;
    opacity: 0;
    position: relative;
    z-index: 0;
    pointer-events: none;
    transition: opacity 0s linear 205ms;
}

Когда мы открываем меню, нам нужно, чтобы оно стало видимым и получило более высокое значение параметра z-index, чтобы div trigger не накрывал его:

.dr-menu.dr-menu-open ul {
    opacity: 1;
    z-index: 200;
    pointer-events: auto;
    transition: opacity 0s linear 0s;
}

Здесь мы используем два перехода – для открывания и закрывания. Когда мы открываем меню, нам нужно, чтобы оно появилось мгновенно, без задержки, а когда мы закрываем его (другими, словами, убираем заданный класс), нам нужно, чтобы это происходило с незначительным замедлением. Эта задержка определяется задержкой последнего пункта в списке.Пункты меню также будут невидимыми, и мы выставим переход для параметра непрозрачности:

.dr-menu ul li {
    display: block;
    margin: 0 0 5px 0;
    opacity: 0;
    transition: opacity 0.3s ease;
}

.dr-menu.dr-menu-open ul li {
    opacity: 1;
}

Теперь, каждый пункт списка будет появляться с разной задержкой: первый пункт будет появляться мгновенно, а последний пункт будет появляться в самом конце:

.dr-menu.dr-menu-open ul li:nth-child(2) {
    transition-delay: 35ms;
}

.dr-menu.dr-menu-open ul li:nth-child(3) {
    transition-delay: 70ms;
}

.dr-menu.dr-menu-open ul li:nth-child(4) {
    transition-delay: 105ms;
}

.dr-menu.dr-menu-open ul li:nth-child(5) {
    transition-delay: 140ms;
}

.dr-menu.dr-menu-open ul li:nth-child(6) {
    transition-delay: 175ms;
}

.dr-menu.dr-menu-open ul li:nth-child(7) {
    transition-delay: 205ms;
}

У ссылок будет небольшой отступ, и в целом мы определим их как inline-blocks:

.dr-menu ul li a {
    display: inline-block;
    padding: 0 20px;
    color: #fff;
}

Также мы изменим цвет при наведении:

.dr-menu ul li a:hover {
    color: #60a773;
}

Последнее, но не менее важное, заключается в определении псевдо-элементов иконки:

.dr-icon:before,
.dr-icon:after {
    position: relative;
    font-family: 'icomoon';
    speak: none;
    font-style: normal;
    font-weight: normal;
    font-variant: normal;
    text-transform: none;
    -webkit-font-smoothing: antialiased;
}

.dr-menu ul .dr-icon:before {
    margin-right: 15px;
}

.dr-icon-bullhorn:before {
    content: "e000";
}

.dr-icon-camera:before {
    content: "e002";
}

.dr-icon-heart:before {
    content: "e003";
}

.dr-icon-settings:before {
    content: "e004";
}

.dr-icon-switch:before {
    content: "e005";
}

.dr-icon-download:before {
    content: "e006";
}

.dr-icon-user:before {
    content: "e001";
}

.dr-icon-menu:before {
    content: "e007";
}

И на этом вся стилизация! Давайте теперь взглянем на javascript.

javascript

Мы создадим небольшой скрипт, который позаботится обо всем функционале. Когда мы кликаем по разделению trigger, нам нужно, чтобы оболочка меню получила класс dr-menu-open. Так как мы собираемся анимировать ярлык, и сместить иконку меню вправо, нам нужно, чтобы закрывание происходило только при клике по иконке меню, как это реализовано в меню Youtube:

var YTMenu = (function() {

    function init() {

        [].slice.call( document.querySelectorAll( '.dr-menu' ) ).forEach( function( el, i ) {

            var trigger = el.querySelector( 'div.dr-trigger' ),
                icon = trigger.querySelector( 'span.dr-icon-menu' ),
                open = false;

            trigger.addEventListener( 'click', function( event ) {
                if( !open ) {
                    el.className += ' dr-menu-open';
                    open = true;
                }
            }, false );

            icon.addEventListener( 'click', function( event ) {
                if( open ) {
                    event.stopPropagation();
                    open = false;
                    el.className = el.className.replace(/bdr-menu-openb/,'');
                    return false;
                }
            }, false );

        } );

    }

    init();

})();

И на этом всё! Мы надеемся, что вам понравилось данное руководство, и вы найдете ему применение!