6 360 Скрипты / Menu & Nav

Адаптивное Retina меню

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

Вы можете сами создать необходимые вам иконки, в каком-нибудь векторном редакторе, например Adobe Illustrator, затем экспортировать их в SVG файлы, и далее импортировать их с помощью инструмента на сайте http://icomoon.io. А для демонстрации, мы сразу воспользуемся этим сервисом и выберем уже готовые иконки, которые нам подходят и скачаем готовый архив с файлами шрифта. (каждую иконку можно настроить дополнительно через сайт, но дефолтных настроек вполне достаточно)


В архиве мы получим 4 формата шрифта - SVG, EOT, TTF и WOFF, а также CSS файл и демо страницу.
Первое что нужно сделать, чтобы использовать эти иконки на своем сайте, это скопировать и вставить содержимое CSS файла, в ваш файл стилей (отредактировав пути), не забыв скопировать и папку со шрифтами на ваш сервер.

HTML

<nav id="menu" class="nav">
    <ul>
        <li>
            <a href="#">
                <span class="icon">
                    <i aria-hidden="true" class="icon-home"></i>
                </span>
                <span>Главная</span>
            </a>
        </li>
        <li>
            <a href="#">
                <span class="icon">
                    <i aria-hidden="true" class="icon-services"></i>
                </span>
                <span>Услуги</span>
            </a>
        </li>
        <li>
            <a href="#">
                <span class="icon">
                    <i aria-hidden="true" class="icon-portfolio"></i>
                </span>
                <span>Портфолио</span>
            </a>
        </li>
        <li>
            <a href="#">
                <span class="icon">
                    <i aria-hidden="true" class="icon-blog"></i>
                </span>
                <span>Блог</span>
            </a>
        </li>
        <li>
            <a href="#">
                <span class="icon">
                    <i aria-hidden="true" class="icon-team"></i>
                </span>
                <span>Команда</span>
            </a>
        </li>
        <li>
            <a href="#">
                <span class="icon">
                    <i aria-hidden="true" class="icon-contact"></i>
                </span>
                <span>Контакты</span>
            </a>
        </li>
    </ul>
</nav>

Чтобы использовать иконку из шрифта, мы просто используем класс "icon-НазваниеИконки" внутри тега <i> (тег span также будет отлично работать). Может быть вы обратили внимание на то, что мы добавили класс no-js к тегу html, он будет изменяться с помощью Modernizr на JS в браузерах в которых включен jаvascript. Если же JS выключен, то Меню у нас будет открыто. Modernizr будем также использовать и для обнаружения touch устройств.

CSS

Замечание: тут мы не будем приводить для свойств CSS префиксы, но в исходниках они будут.
Глобальный CSS, который будет применяться при всех размерах окна браузера:

.nav ul {
    max-width: 1240px;
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 1.5em;
    font-weight: 300;
}
.nav li span {
    display: block;
}
.nav a {
    display: block;
    color: rgba(249, 249, 249, .9);
    text-decoration: none;
    transition: color .5s, background .5s, height .5s;
}
.nav i{
    /* Сделает шрифт более мягче для Chrome */
    transform: translate3d(0, 0, 0);
}
/* Удаляем синий Вебкит фон */
a, button {
    -webkit-tap-highlight-color: rgba(0,0,0,0);
}

Первая маленькая анимация для всей навигации. Увеличиваем прозрачность для всех элементов, ккроме того, на который мы навели курсор:

.no-touch .nav ul:hover a {
    color: rgba(249, 249, 249, .5);
}
.no-touch .nav ul:hover a:hover {
    color: rgba(249, 249, 249, 0.99);
}

Теперь добавим для всех элементов различные цвета:

.nav li:nth-child(6n+1) {
    background: rgb(208, 101, 3);
}
 
.nav li:nth-child(6n+2) {
    background: rgb(233, 147, 26);
}
 
.nav li:nth-child(6n+3) {
    background: rgb(22, 145, 190);
}
 
.nav li:nth-child(6n+4) {
    background: rgb(22, 107, 162);
}
 
.nav li:nth-child(6n+5) {
    background: rgb(27, 54, 71);
}
 
.nav li:nth-child(6n+6) {
    background: rgb(21, 40, 54);
}

Тут мы уже используем CSS возможности ::nth-child для выбора элементов списка.
Используя min-width в media query, мы можем ориентироваться на экраны с размером более 800px и использовать таким образом хорошую горизонтальную навигацию.

@media (min-width: 50em) {
 
    /* Трансформирование списка в горизонтальную навигацию */
    .nav li {
        float: left;
        width: 16.66666666666667%;
        text-align: center;
        transition: border .5s;
    }
 
    .nav a {
        display: block;
        width: auto;
    }

Продолжаем использовать ::nth-child для выбора элементов списка и добавления границы в 4px. Граница 4px будет добавляться при событиях hover, а также и focus и active - чтобы не потерялась работоспособность и на touch устройствах.

.no-touch .nav li:nth-child(6n+1) a:hover,
.no-touch .nav li:nth-child(6n+1) a:active,
.no-touch .nav li:nth-child(6n+1) a:focus {
    border-bottom: 4px solid rgb(174, 78, 1);
}
 
.no-touch .nav li:nth-child(6n+2) a:hover,
.no-touch .nav li:nth-child(6n+2) a:active,
.no-touch .nav li:nth-child(6n+2) a:focus {
    border-bottom: 4px solid rgb(191, 117, 20);
}
 
.no-touch .nav li:nth-child(6n+3) a:hover,
.no-touch .nav li:nth-child(6n+3) a:active,
.no-touch .nav li:nth-child(6n+3) a:focus {
    border-bottom: 4px solid rgb(12, 110, 149);
}
 
.no-touch .nav li:nth-child(6n+4) a:hover,
.no-touch .nav li:nth-child(6n+4) a:active,
.no-touch .nav li:nth-child(6n+4) a:focus {
    border-bottom: 4px solid rgb(10, 75, 117);
}
 
.no-touch .nav li:nth-child(6n+5) a:hover,
.no-touch .nav li:nth-child(6n+5) a:active,
.no-touch .nav li:nth-child(6n+5) a:focus {
    border-bottom: 4px solid rgb(16, 34, 44);
}
 
.no-touch .nav li:nth-child(6n+6) a:hover,
.no-touch .nav li:nth-child(6n+6) a:active,
.no-touch .nav li:nth-child(6n+6) a:focus {
    border-bottom: 4px solid rgb(9, 18, 25);
}

Размещаем иконки и текст:

.icon {
    padding-top: 1.4em;
}
 
.icon + span {
    margin-top: 2.1em;
    transition: margin .5s;
}

Анимируем высоту элементов при наведении (hover):

/* Animating the height of the element*/
.nav a {
    height: 9em;
}
 
.no-touch .nav a:hover ,
.no-touch .nav a:active ,
.no-touch .nav a:focus {
    height: 10em;
} 
 
/* Making the text follow the height animation */
.no-touch .nav a:hover .icon + span {
    margin-top: 3.2em;
    transition: margin .5s;
}

Далее позиционируем иконки и готовим их к CSS transition:

.nav i {
    position: relative;
    display: inline-block;
    margin: 0 auto;
    padding: 0.4em;
    border-radius: 50%;
    font-size: 1.8em;
    box-shadow: 0 0 0 0.8em transparent;
    background: rgba(255,255,255,0.1);
    transform: translate3d(0, 0, 0);
    transition: box-shadow .6s ease-in-out;
}

Для создания визуального эффекта - плавного перехода тени с изменением размера от 0.8em до 0, и изменение прозрачности. Также закрываем первый media query:

    .no-touch .nav a:hover i,
    .no-touch .nav a:active i,
    .no-touch .nav a:focus i {    
        box-shadow: 0 0 0px 0px rgba(255,255,255,0.2);
        transition: box-shadow .4s ease-in-out;
    }
}

Пишем второй media query для экранов с размерами от 800px до 980px:

@media (min-width: 50em) and (max-width: 61.250em) {
    .nav ul {
        font-size: 1.2em;
    }
}

Теперь, когда мы закончили с "десктопными" версиями (или планшетниками с большим разрешением), примемся за CSS для экранов с разрешением менее 800px, здесь это составляет 49.938em (использовать будем max-width).

/* The "tablet" and "mobile" version */
 
@media (max-width: 49.938em) {    
    
    /* Instead of adding a border, we transition the background color */
    .no-touch .nav ul li:nth-child(6n+1) a:hover,
    .no-touch .nav ul li:nth-child(6n+1) a:active,
    .no-touch .nav ul li:nth-child(6n+1) a:focus {
        background: rgb(227, 119, 20);
    }
 
    .no-touch .nav li:nth-child(6n+2) a:hover,
    .no-touch .nav li:nth-child(6n+2) a:active,
    .no-touch .nav li:nth-child(6n+2) a:focus {
        background: rgb(245, 160, 41);
    }
 
    .no-touch .nav li:nth-child(6n+3) a:hover,
    .no-touch .nav li:nth-child(6n+3) a:active,
    .no-touch .nav li:nth-child(6n+3) a:focus {
        background: rgb(44, 168, 219);
    }
 
    .no-touch .nav li:nth-child(6n+4) a:hover,
    .no-touch .nav li:nth-child(6n+4) a:active,
    .no-touch .nav li:nth-child(6n+4) a:focus {
        background: rgb(31, 120, 176);
    }
 
    .no-touch .nav li:nth-child(6n+5) a:hover,
    .no-touch .nav li:nth-child(6n+5) a:active,
    .no-touch .nav li:nth-child(6n+5) a:focus {
        background: rgb(39, 70, 90);
    }
 
    .no-touch .nav li:nth-child(6n+6) a:hover,
    .no-touch .nav li:nth-child(6n+6) a:active,
    .no-touch .nav li:nth-child(6n+6) a:focus {
        background: rgb(32, 54, 68);
    }
 
    .nav ul li {
        transition: background 0.5s;
    } 
 
}

Для экранов с размерами между 520px (32.5em) и 799px (49.938em) мы хотим отображать наше меню в два столбца и в три строки. Мы добавили ещё отступов (padding) для элементов, для более удобного касания пальцами, а также иконку будем отображать слева, а текст справа.

/* CSS for a 2x3 columns version */
 
@media (min-width: 32.5em) and (max-width: 49.938em) {
    
    /* Creating the 2 column layout using floating elements once again */
    .nav li {
        display: block;
        float: left;
        width: 50%;
    }
    
    /* Adding some padding to make the elements look nicer*/
    .nav a {
        padding: 0.8em;   
    }
 
    /* Displaying the icons on the left, and the text on the right side using inline-block */
    .nav li span,
    .nav li span.icon {
        display: inline-block;
    }
 
    .nav li span.icon {
        width: 50%;
    }
 
    .nav li .icon + span {
        font-size: 1em;
    }
 
    .icon + span {
        position: relative;
        top: -0.2em;
    }

Анимация используемая на экранах с большим разрешением слишком сложна, чтобы вписаться в маленькие экраны, поэтому мы сделаем её проще, и ограничимся анимацией границ. И в конце закрываем наш media query.

/* Adapting the icons to animate the size and border of the rounded background in a more discreet way */
    .nav li i {
        display: inline-block;
        padding: 8% 9%;
        border: 4px solid transparent;
        border-radius: 50%;
        font-size: 1.5em;
        background: rgba(255,255,255,0.1);
        transition: border .5s;
    }
 
    /* Transition effect on the border color */
    .no-touch .nav li:hover i,
    .no-touch .nav li:active i,
    .no-touch .nav li:focus i {
        border: 4px solid rgba(255,255,255,0.1);
    }
 
}

Для маленьких экранов мы адаптируем размер шрифта и ширину:

@media (min-width: 32.5em) and (max-width: 38.688em) {
    
    .nav li span.icon {
        width: 50%;
    }
 
    .nav li .icon + span {
        font-size: 0.9em;
    }
}

JS

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

        <script>
            //  Функция для изменения класса
            var changeClass = function (r,className1,className2) {
                var regex = new RegExp("(?:^|\\s+)" + className1 + "(?:\\s+|$)");
                if( regex.test(r.className) ) {
                    r.className = r.className.replace(regex,' '+className2+' ');
                }
                else{
                    r.className = r.className.replace(new RegExp("(?:^|\\s+)" + className2 + "(?:\\s+|$)"),' '+className1+' ');
                }
                return r.className;
            };   
 
            //  Создание кнопки меню в JS для маленьких экранов
            var menuElements = document.getElementById('menu');
            menuElements.insertAdjacentHTML('afterBegin','<button type="button" id="menutoggle" class="navtoogle" aria-hidden="true"><i aria-hidden="true" class="icon-menu"> </i> Меню</button>');
 
            // Переключение класса по клику - показать/скрыть меню
            document.getElementById('menutoggle').onclick = function() {
                changeClass(this, 'navtoogle active', 'navtoogle');
            }
        </script>

Для более чистого HTML кода, мы решили создать кнопку "Меню" и вставить её в DOM, используя jаvascript.
Функция changeClass поможет в переключении между активным и не активным классом, когда пользователь кликает по кнопке.
JS код кнопки у нас теперь есть, осталось стилизовать её:

/* Styling the toggle menu link and hiding it */
.nav .navtoogle{
    display: none;
    width: 100%;
    padding: 0.5em 0.5em 0.8em;
    font-family: 'Lato',Calibri,Arial,sans-serif;
    font-weight: normal;
    text-align: left;
    color: rgb(7, 16, 15);
    font-size: 1.2em;
    background: none; 
    border: none;
    border-bottom: 4px solid rgb(221, 221, 221);
    cursor: pointer;
}
 
.icon-menu {
    position: relative;
    top: 3px;
    line-height: 0;
    font-size: 1.6em;
}

По умолчанию, кнопка "Меню" скрыта. Будем отображать её на экранах не более 519px (32.438px):

@media (max-width: 32.438em) {
    .nav .navtoogle{
        margin: 0;
        display: block;
    }

Анимируем высоту навигации, когда кнопка нажата. Для закрытия навигации, мы назначим ей высоту в 0em, при открытии - назначим max-height в 30em. Если jаvascript не включен, то кнопки у нас не будет, так как мы используем класс no-js и навигация у нас будет всегда отображаться на экране.

.no-js .nav ul {
    max-height: 30em;
    overflow: hidden;
}

Когда JS включен, мы скрываем по умолчанию меню, и показываем его, когда пользователь кликает по кнопке, которой назначается active класс:

/* When jаvascript is enabled, we hide the menu */
.js .nav ul {
    max-height: 0em;
    overflow: hidden;
}
 
/* Displaying the menu when the user has clicked on the button */
.js .nav .active + ul {   
    max-height: 30em;
    overflow: hidden;
    transition: max-height .4s;
}

Для маленьких экранов адаптируем представление навигации, преобразуя в список с иконками слева от текста:

.nav li span {
    display: inline-block;
    height: 100%;
}
 
.nav a {
    padding: 0.5em;   
}
 
.icon + span {
    margin-left: 1em;
    font-size: 0.8em;
}

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

.nav li:nth-child(6n+1) {
    border-left: 8px solid rgb(174, 78, 1);
}
 
.nav li:nth-child(6n+2) {
    border-left: 8px solid rgb(191, 117, 20);
}
 
.nav li:nth-child(6n+3) {
    border-left: 8px solid rgb(13, 111, 150);
}
 
.nav li:nth-child(6n+4) {
    border-left: 8px solid rgb(10, 75, 117);
}
 
.nav li:nth-child(6n+5) {
    border-left: 8px solid rgb(16, 34, 44);
}
 
.nav li:nth-child(6n+6) {
    border-left: 8px solid rgb(9, 18, 25);
}

И вот у нас получилась отличная навигация. Но на мобильных сенсорных устройствах, её элементы могут вызвать трудности при использовании. Использование в нашем случае Modernizr позволяет обнаружить сенсорные устройства, и добавить touch класс к документу, что позволит нам непосредственно для сенсорных устройств сделать элменты навигации более крупными. И наконец закрываем наш последний media query:

    /* make the nav bigger on touch screens */
    .touch .nav a {
        padding: 0.8em;
    }
}

Вот мы с вами и сделали адаптивной меню с поддержкой retina экранов. Успехов!

Скачать 3118Загрузок 12,74 Kb
Демо

Комментарии

  • Facebook
  • Вконтакте

Похожие статьи