Адаптивное меню с поддержкой retina

от автора

В этой статье очень подробно описано пошаговое создание адаптивного меню для сайта с несколькими вариантами компоновки элементов (в зависимости от размера экрана девайса). Для поддержки retina-экранов используется иконочный шрифт.

Демо / Скачать исходники

Подготовка иконочного шрифта

Создание иконочного шрифта вручную может доставить проблем, но к счастью, имеются веб-сервисы, которые облегчают такие задачи разработчику. IcoMoon — один из таких инструментов.

В первую очередь следует подготовить SVG-файлы иконок и импортировать их в IcoMoon:

На сайте уже есть множество готовых файлов для создания шрифта, можно частично использовать их. Каждой иконке можно назначить клавишу:

На выходе получается ZIP-файл со шрифтами в четырех форматах: SVG, EOT, TTF и WOFF, а также CSS файл и демо-страница. Кстати, чтобы шрифт лучше смотрелся в Chrome, можно использовать специальных хак.

HTML

Разметка нашего меню:

<nav  id="menu" class="nav">       <ul>         <li>             <a  href="#" title="">                 <span  class="icon"> <i aria-hidden="true"  class="icon-home"></i></span><span>Home</span>             </a>         </li>         <li>                   <a href="#" title=""><span class="icon"> <i aria-hidden="true" class="icon-services"></i></span><span>Services</span></a>            </li>          <li>             <a  href="#" title=""><span  class="icon"><i  aria-hidden="true" class="icon-portfolio"></i></span><span>Portfolio</span></a>         </li>         <li>             <a  href="#" title=""><span  class="icon"><i  aria-hidden="true" class="icon-blog"></i></span><span>Blog</span></a>          </li>         <li>             <a  href="#" title=""><span  class="icon"><i  aria-hidden="true" class="icon-team"></i></span><span>The  team</span></a>             </li>         <li>             <a  href="#" title=""><span  class="icon"><i  aria-hidden="true" class="icon-contact"></i></span><span>Contact</span></a>         </li>     </ul> </nav> 

Для добавления иконочного шрифта используем CSS-класс «icon-iconname» внутри тега i. Также добавим класс «no-js» в body, который будет меняться на класс «js» с помощью Modernizr. Это нужно для того, чтобы меню корректно работало у пользователей с отключенным JavaScript.

CSS и JavaScript

Основной 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); }   /* Убирает синий Webkit-фон при тапе на тач-скрине */   a, button {     -webkit-tap-highlight-color: rgba(0,0,0,0); } 

Основной hover-эффект:

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

Добавляем фоновый цвет для элементов меню. Благодаря использованию nth-child можно добавлять сколько угодно элементов списка, цвет будет наследоваться:

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

Используем media query для изменения формы меню на меньшем экране:

@media (min-width: 50em) {       /* Transforms the list into a horizontal navigation */     .nav li {         float: left;         width: 16.66666666666667%;         text-align: center;         transition: border .5s;     }       .nav a {         display: block;         width: auto;     } 

Добавляем border разных цветов для элементов меню:

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

Небольшая анимация меню:

/* Пункт меню увеличивается по высоте*/ .nav a {     height: 9em; }   .no-touch .nav a:hover , .no-touch .nav a:active , .no-touch .nav a:focus {     height: 10em; }      /* Движение текста */ .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; }    

Для нужного визуального эффекта меняем тень элемента:

    .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, для экранов от 800 до 980 пикселей:

@media (min-width: 50em) and (max-width: 61.250em) {       /* Size and font adjustments to make it fit better */     .nav ul {         font-size: 1.2em;     }   } 

Закончили с CSS для «desktop» версии меню, переходим к «tablet» и «mobile»:

/*  "tablet" и "mobile" версии*/   @media (max-width: 49.938em) {                 /* Вместо добавления border модифицируем цвет фона */     .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) меню должно отображаться в две колонки. Добавляем немного отступов для удобного тапа на тач-скринах:

  @media (min-width: 32.5em) and (max-width: 49.938em) {           /* Делаем две колонки */     .nav li {         display: block;         float: left;         width: 50%;     }           /* Добавляем отступ */     .nav a {         padding: 0.8em;          }       /* Перемещаем иконки и текст в левую часть элементов меню */     .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;     } 

Навигация большого экрана слишком сложна для мобильных устройств, поэтому упрощаем ее:

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

Для самых маленьких экранов необходимо скрыть всю навигацию, оставив только кнопку «Menu», по клику на которую открываются все пункты. Используем JavaScript:

//  функция для смены класса 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; };     //  кнопка для маленьких экранов 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> Menu</button>');   //  меняем класс для скрытия/отображения меню document.getElementById('menutoggle').onclick = function() {     changeClass(this, 'navtoogle active', 'navtoogle'); }   // document click для скрытия меню // http://tympanus.net/codrops/2013/05/08/responsive-retina-ready-menu/comment-page-2/#comment-438918 document.onclick = function(e) {     var mobileButton = document.getElementById('menutoggle'),         buttonStyle =  mobileButton.currentStyle ? mobileButton.currentStyle.display : getComputedStyle(mobileButton, null).display;       if(buttonStyle === 'block' && e.target !== mobileButton && new RegExp(' ' + 'active' + ' ').test(' ' + mobileButton.className + ' ')) {         changeClass(mobileButton, 'navtoogle active', 'navtoogle');     } } 

Для более чистого HTML-кода кнопка «Menu» создается непосредственно в JavaScript. CSS для кнопки:

.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; }   .navtoogle i{     z-index:-1; }   .icon-menu {     position: relative;     top: 3px;     line-height: 0;     font-size: 1.6em; } 

По умолчанию кнопка скрыта, появляется при размере экрана менее 519px (32.438em):

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

Используем класс «no-js» для отображения меню у пользователей без поддержки JavaScript:

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

Когда JavaScript поддерживается, скрываем меню:

.js .nav ul {     max-height: 0em;     overflow: hidden; }   /* Отображение меню по клику на кнопку */ .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; } 

Добавляем border слева:

.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»:

 .touch .nav a {         padding: 0.8em;     } } 

Вот и все, получилась красивая retina-ready навигация, хорошо отображающаяся на любых устройствах!

ссылка на оригинал статьи http://habrahabr.ru/post/187460/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *