Сегодня мы будем создавать красочное и отзывчивое, адаптивное или респонсив меню, которое будет хорошо смотреться и на Retina-дисплеях. Меню автоматически видоизменяется в зависимости от размера окна браузера:
- Горизонтальное меню на мониторах компьютеров
- Двухколоночное вертикальное меню на планшетах
- На смартфонах меню будет скрыто и будет добавлена ссылка для его отображения или скрытия.
Изображения к меню мы вставим через шрифт из иконок, чтобы не было потери их качества на устройствах с Retina-дисплеями.
Смотреть Демо
Подготавливаем шрифт из иконок
Самостоятельное создание собственного шрифта иконок будет довольно сложным, но с инструментами, как IcoMoon этот процесс доведен до автоматизма. Шрифт из иконок ведет себя так же, как и любой другой шрифт, так что вы можете с легкостью менять цвет, размеры, и потери качества не произойдет. Они идеально подходят для Retina-дисплеев, т.к. нет необходимости использовать несколько изображений разного размера.
Перейдем к действиям. Перейдите к сервису IcoMoon, чтобы создать шрифт с иконками. Там вы можете выбрать уже доступные иконки для пунктов вашего меню, или предварительно нарисовать их самому в векторном редакторе, как Adobe Illustrator или Inscape, и добавить их в свой шрифт.
После того, как вы выберите нужные иконки, жмите кнопку “Font”. На этой странице мы можем выбрать параметры кодирования для шрифта и назначить для каждой иконки букву, которую она заменит в тексте. Но я рекомендую использовать параметры по умолчанию, они и так работают очень хорошо.
Нажав на кнопку “Download” мы скачиваем ZIP-архив, в котором находится наш шрифт в 4-х форматах, CSS-стили и демонстрационная страница.
Чтобы все заработало, скопируйте папку шрифтов в папку со страницей и в самое начало вашего файла стилей вставьте стили от IcoMoon. Еще, чтобы шрифт выглядел лучше на Chrome под ОС Windows, вы можете попробовать следующий хак.
HTML код меню
HTML-разметка нашего меню выглядит следующим образом:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<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, но они есть в демонстрации.
Глобальные стили будут применяться для всех размеров экранов:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
/* 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);
}
|
Первый небольшой эффект: снизим прозрачность всех пунктов меню, за исключением одного, на который наведен курсор.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
/* 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), зададим вывод горизонтального меню
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@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 пикселя с соответствующим цветом для элементов меню при наведении курсора, фокусе и клике, чтобы эффект заработал на сенсорных устройствах и с клавиатуры.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
/* 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);
}
|
Теперь разместим иконки и текст.
1
2
3
4
5
6
7
8
9
10
|
/* Placing the icon */
.icon {
padding-top: 1.4em;
}
.icon + span {
margin-top: 2.1em;
transition: margin .5s;
}
|
Изменим высоту элементов, при наведении (она плавно увеличится, т.к. мы уже применяли свойство transition):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/* 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;
}
|
Позиционируем иконки и приготовим их к плавному переходу
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/* 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;
}
|
Добавим визуальные эффекты, как тень и плавный переход, и завершаем первый медиа запрос
1
2
3
4
5
6
7
8
9
|
/* 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 пикселей:
1
2
3
4
5
6
7
8
|
@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 и больше), перейдем к стилизации меню на планшетах и смартфонах.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
/* 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 строки. Теперь значок будет слева, а текст справа.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
/* 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;
}
|
Анимация под большой экран слишком сложна, чтобы вписаться в небольшие экраны, поэтому мы адаптируем ее. Сделаем ее более простой и сдержанной и завершаем очередной медиа запрос.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
/* 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);
}
}
|
Адаптируем размер шрифта и ширину для маленьких экранов
1
2
3
4
5
6
7
8
9
10
11
|
/* 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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
// 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','');
// Toggle the class on click to show / hide the menu
document.getElementById('menutoggle').onclick = function() {
changeClass(this, 'navtoogle active', 'navtoogle');
}
|
Для того чтобы иметь более чистый HTML, я решил создать кнопку “Меню” и вставить его в DOM используя JavaScript. Функция changeClass помогает нам для переключения между активными и не активным классом, когда пользователь нажимает на кнопку.
Следующие стили для кнопки “Меню”:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
/* 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 пикселей:
1
2
3
4
5
6
7
|
@media (max-width: 32.438em) {
/* Unhiding the styled menu link */
.nav .navtoogle{
margin: 0;
display: block;
}
|
Мы анимируем высоту навигации после клика по кнопке. Для закрытия навигации, мы задаем ей высоту в 0em, чтобы открыть ее, мы задаем максимальную высоту в 30em. Если JavaScript не включен, мы используем класс no-js для постоянного отображения навигации.
1
2
3
4
5
6
7
|
/* 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:
1
2
3
4
5
6
7
8
9
10
11
12
|
/* 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;
}
|
Мы адаптируем макет для небольших экранов, представляя навигацию в список элементов со значком слева и текстом с права:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/* 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 пикселей с клевым цветом:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
/* 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 для определения сенсорного экрана. И на сенсорном экране мы увеличим элементы меню за счет увеличения внутреннего отступа и завершаем последний медиа запрос.
1
2
3
4
|
/* make the nav bigger on touch screens */
.touch .nav a {
padding: 0.8em;
}
|
Теперь все готово! Мы сделали клевое адаптивное меню, дружелюбное к сенсорам и Retina-экранам. Думаю вам понравилось!
Это не единственный вариант создания такого рода навигационного меню. В наших предыдущих статьях вы можете посмотреть как сдлеать другие респонсив меню.
Данный урок приготовлен для вас командой сайта WebDesignMagazine.ru