Сегодня мы будем создавать красочное и отзывчивое, адаптивное или респонсив меню, которое будет хорошо смотреться и на Retina-дисплеях. Меню автоматически видоизменяется в зависимости от размера окна браузера:
- Горизонтальное меню на мониторах компьютеров
- Двухколоночное вертикальное меню на планшетах
- На смартфонах меню будет скрыто и будет добавлена ссылка для его отображения или скрытия.
- Изображения к меню мы вставим через шрифт из иконок, чтобы не было потери их качества на устройствах с Retina-дисплеями.
Подготавливаем шрифт из иконок
Самостоятельное создание собственного шрифта иконок будет довольно сложным, но с инструментами, как IcoMoon этот процесс доведен до автоматизма. Шрифт из иконок ведет себя так же, как и любой другой шрифт, так что вы можете с легкостью менять цвет, размеры, и потери качества не произойдет. Они идеально подходят для Retina-дисплеев, т.к. нет необходимости использовать несколько изображений разного размера.
Перейдем к действиям. Перейдите к сервису IcoMoon, чтобы создать шрифт с иконками. Там вы можете выбрать уже доступные иконки для пунктов вашего меню, или предварительно нарисовать их самому в векторном редакторе, как Adobe Illustrator или Inscape, и добавить их в свой шрифт.
После того, как вы выберите нужные иконки, жмите кнопку “Font”. На этой странице мы можем выбрать параметры кодирования для шрифта и назначить для каждой иконки букву, которую она заменит в тексте. Но я рекомендую использовать параметры по умолчанию, они и так работают очень хорошо.
Нажав на кнопку “Download” мы скачиваем ZIP-архив, в котором находится наш шрифт в 4-х форматах, CSS-стили и демонстрационная страница.
Чтобы все заработало, скопируйте папку шрифтов в папку со страницей и в самое начало вашего файла стилей вставьте стили от IcoMoon. Еще, чтобы шрифт выглядел лучше на Chrome под ОС Windows, вы можете попробовать следующий хак.
HTML код меню
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>
Чтобы использовать нашим иконочным шрифтом, мы добавляем класс icon-iconname к элементу <i>. Хоть здесь и не обозначено, но тег <body> должен иметь класс no-js (который будет изменен на js через Modernizr). Идея состоит в том, чтобы можно было оставить меню открытым, если пользователь отключил JavaScript.
CSS и JavaScript
Обратите внимание, что в уроке опущены префиксы браузеров для свойств CSS3, но они есть в демонстрации.
Глобальные стили будут применяться для всех размеров экранов:
/* Global CSS that are applied for all screen sizes */ .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{ /* Make the font smoother for Chrome */ transform: translate3d(0, 0, 0); } /* Remove the blue Webkit background when element is tapped */ a, button { -webkit-tap-highlight-color: rgba(0,0,0,0); }
Первый небольшой эффект: снизим прозрачность всех пунктов меню, за исключением одного, на который наведен курсор.
/* Hover effect for the whole navigation to make the hovered item stand out */ .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); }[/css] Затем мы хотим добавить интересные цвета фона для всех элементов. Приведенный ниже код использует :nth-child технику для отбора элементов. [php].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); }
Используя медиа запрос для экранов с минимальной шириной в 800 пикселей (50em), зададим вывод горизонтального меню
@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; }
Продолжаем предыдущий код. Добавим границу снизу в 4 пикселя с соответствующим цветом для элементов меню при наведении курсора, фокусе и клике, чтобы эффект заработал на сенсорных устройствах и с клавиатуры.
/* hover, focused and active effects that add a little colored border to the different items */ .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); }
Теперь разместим иконки и текст.
/* Placing the icon */ .icon { padding-top: 1.4em; } .icon + span { margin-top: 2.1em; transition: margin .5s; }
Изменим высоту элементов, при наведении (она плавно увеличится, т.к. мы уже применяли свойство transition):
/* 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; }
Позиционируем иконки и приготовим их к плавному переходу
/* Positioning the icons and preparing for the animation*/ .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; }
Добавим визуальные эффекты, как тень и плавный переход, и завершаем первый медиа запрос
/* Animate the box-shadow to create the effect */ .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; } }
Создаем еще один медиа запрос для экранов с шириной между 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; } }
Теперь, когда мы закончили “настольную” версию меню (конечно же в кавычках, так как все больше и больше планшетов имеют ширину экрана 1024px и больше), перейдем к стилизации меню на планшетах и смартфонах.
/* 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; } }
Для размера экрана между 520 и 799 пикселей (только для планшетов), мы хотим показать наше меню в 2 столбца и 3 строки. Теперь значок будет слева, а текст справа.
/* 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; }
Анимация под большой экран слишком сложна, чтобы вписаться в небольшие экраны, поэтому мы адаптируем ее. Сделаем ее более простой и сдержанной и завершаем очередной медиа запрос.
/* 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); } }
Адаптируем размер шрифта и ширину для маленьких экранов
/* Adapting the font size and width for smaller screns*/ @media (min-width: 32.5em) and (max-width: 38.688em) { .nav li span.icon { width: 50%; } .nav li .icon + span { font-size: 0.9em; } }
Для очень маленьких экранов мы cпрячем навигацию и добавим кнопку “Меню”, на которую посетитель нажмет для показа навигации. Чтобы сделать это, мы опираемся на несколько строк JavaScript:
// The function to change the class 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; }; // Creating our button for smaller screens 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>'); // Toggle the class on click to show / hide the menu document.getElementById('menutoggle').onclick = function() { changeClass(this, 'navtoogle active', 'navtoogle'); }
Для того чтобы иметь более чистый HTML, я решил создать кнопку “Меню” и вставить его в DOM используя JavaScript. Функция changeClass помогает нам для переключения между активными и не активным классом, когда пользователь нажимает на кнопку.
Следующие стили для кнопки “Меню”:
/* 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; }
По умолчанию, данная кнопка скрыта. Мы ее отобразим на экранах шириной не более 519 пикселей:
@media (max-width: 32.438em) { /* Unhiding the styled menu link */ .nav .navtoogle{ margin: 0; display: block; }
Мы анимируем высоту навигации после клика по кнопке. Для закрытия навигации, мы задаем ей высоту в 0em, чтобы открыть ее, мы задаем максимальную высоту в 30em. Если JavaScript не включен, мы используем класс no-js для постоянного отображения навигации.
/* Animating the height of the navigation when the button is clicked */ /* If JavaScript is disabled, the menu stays open */ .no-js .nav ul { max-height: 30em; overflow: hidden; }
Когда JavaScript включен, мы скрываем меню по умолчанию, и показываем его, когда пользователь нажимает на кнопку, после чего навигация получает класс active:
/* When JavaScript 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; }
Мы адаптируем макет для небольших экранов, представляя навигацию в список элементов со значком слева и текстом с права:
/* Adapting the layout of the menu for smaller screens: icon on the left and text on the right */ .nav li span { display: inline-block; height: 100%; } .nav a { padding: 0.5em; } .icon + span { margin-left: 1em; font-size: 0.8em; }
Также добавляем границу слева в 8 пикселей с клевым цветом:
/* Adding a left border of 8 px with a different color for each menu item*/ .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 для определения сенсорного экрана. И на сенсорном экране мы увеличим элементы меню за счет увеличения внутреннего отступа и завершаем последний медиа запрос.
/* make the nav bigger on touch screens */ .touch .nav a { padding: 0.8em; }
Теперь все готово! Мы сделали клевое адаптивное меню, дружелюбное к сенсорам и Retina-экранам. Думаю вам понравилось!
Высоких конверсий!