Адаптивное 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 экранов. Успехов!