...

понедельник, 22 июля 2013 г.

[Перевод] Адаптивное меню с поддержкой 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 навигация, хорошо отображающаяся на любых устройствах!


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends: 'You Say What You Like, Because They Like What You Say' - http://www.medialens.org/index.php/alerts/alert-archive/alerts-2013/731-you-say-what-you-like-because-they-like-what-you-say.html


Комментариев нет:

Отправить комментарий