Адаптивное меню
Существует множество техник в адаптивном дизайне, чтобы приспособить навигацию сайта к маленьким экранам. Сегодня мы рассмотрим четыре основных техники, их преимущества и недостатки.
Три из них основаны на чистом CSS, одна техника содержит немного javascript.
До того как начать
В коде для статьи не используются вендорные префиксы, это сделано для лучшего понимания CSS. Более сложные примеры на CSS представлены в SCSS.
Все концепции основаны на нижеприведенной простой HTML-структуре, которую я называю "основа меню". Атрибут
role
используется для указания применяемой концепции (полностью горизонтальное меню (full-horizontal), выборка (select), обычный раскрывающийся список (custom-dropdown) и off-canvas.
<nav role="">
<ul>
<li><a href="#">Stream</a></li>
<li><a href="#">Lab</a></li>
<li><a href="#">Projects</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
</ul>
</nav>?
Для экранов с маленьким разрешением я буду использовать
media query
.
@media screen and (max-width: 44em) {
}
Полностью горизонтальное адаптивное меню
Наиболее простой путь, так как для маленьких экранов мы всего лишь сделаем у элементов полную ширину.
HTML
<nav role="full-horizontal">
<ul>
<li><a href="#">Stream</a></li>
<li><a href="#">Lab</a></li>
<li><a href="#">Projects</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
</ul>
</nav>
CSS
@media screen and (max-width: 44em) {
.first nav[role="full-horizontal"] ul > li {
width: 100%;
}
}
На экранах с большим разрешением:
Вот как это выглядит на маленьком экране с установленными стилями:
Преимущества:
- отсутствует javascript
- Простой CSS и HTML
Недостатки:
- Резервирует под себя много пространства
Адаптивное меню: "Выборка"
Концепция построена так: на маленьких экранах основное меню скрывается и показывается выпадающий список.
Чтобы добиться такого эффекта, нам нужно расширить базовую HTML-структуру и добавить код для выпадающего списка. Также потребуется код javascript, который по событию onchange тега
select
будет менять
window.location
на текущее значение атрибута
value
.
HTML
<nav role="select">
<!-- basic menu goes here -->
<select onchange="if (this.value) window.location.href = this.value;">
<option value="#">Stream</option>
<option value="#">Lab</option>
<option value="#">Projects</option>
<option value="#">About</option>
<option value="#">Contact</option>
</select>
</nav>
Скрываем выпадающий список на больших экранах:
CSS
.second nav[role="select"] > select {
display: none;
}
На маленьких экранах мы скроем основное меню и откроем выпадающий список. Чтобы помочь пользователю распознать наше меню добавим псевдо-элемент с текстом "меню".
CSS
@media screen and (max-width: 44em) {
nav[role="select"] ul {
display: none;
}
nav[role="select"]:after {
position: absolute;
z-index: -1;
content: "Menu";
right: 0;
bottom: -1.75em;
background: rgba(174, 86, 168, 0.4);
padding: .15em .55em;
}
nav[role="select"] select {
display: block;
user-select: none;
cursor: pointer;
width: 100%;
padding: .55em .45em;
border: none;
background-color: rgba(174, 86, 168, 0.25);
font: 1.2em 'Exo', sans-serif;
}
}
Вот как это выглядит на маленьком экране со стилями используемыми в статье:
Преимущества:
- Не требуется много пространства
- Нативные элементы управления
Недостатки:
- Требуется javascript
- Дублируемый контент
- Чтобы стилизовать select потребуется приложить усилия
Обычный раскрывающийся список
Базовое меню скрывается на экранах с маленьким разрешением, взамен же появляются элементы
input
и
label
(смотрите использование
checkbox hack
). Когда пользователь кликает по элементу
label
открывается список с элементами меню.
HTML
<nav role="custom-dropdown">
<!-- Advanced Checkbox Hack (see description below) -->
<!-- basic menu goes here -->
</nav>
Проблемы, связанные с checkbox hack
Существуют две проблемы с настройками checkbox hack:
-
Не работает на мобильных версиях Safari (IOA < 6). Невозможно кликом по
label
переключитьinput
из-за бага. Чтобы решить это проблему необходимо элементуlabel
добавить пустьonclick
. - Не работает в браузере Android (Android <= 4.1.2). Одно время у webkit присутствовал баг, суть которого в том, что родственный комбинатор, или смежный комбинатор, не мог работать в связке с псевдоклассом.
CSS
h1 ~ p { color: black; }
h1:hover ~ p { color: red; }
Поэтому не добьемся никакого эффекта, используя псевдокласс
:checked
совместно с родственным комбинатором. Баг был исправлен в WebKit 535.1 (Chrome 13) и в WebKit для Android 4.1.2 is 534.30.
Лучшее решение использовать фейковую анимацию для тега
body
.
Собирая все вместе воедино, мы получим расширенный checkbox hack:
HTML
<!-- Fix for iOS -->
<input type="checkbox" id="menu">
<label for="menu" onclick></label>
CSS
/* Fix for Android */
body {
-webkit-animation: bugfix infinite 1s;
}
@-webkit-keyframes bugfix {
from { padding: 0; }
to { padding: 0; }
}
/* default checkbox */
input[type=checkbox] {
position: absolute;
top: -9999px;
left: -9999px;
}
label {
cursor: pointer;
user-select: none;
}
Для больших экранов скрываем элемент
label
:
CSS
nav[role="custom-dropdown"] label {
display: none;
}
Для экранов с маленьким разрешением мы скрываем основное меню и открываем
label
. Чтобы помочь пользователю опознать меню, добавим псевдоэлемент с текстом = (в качестве значения для content будем использовать код “
\2261
”). Когда пользователь кликает по элементу
label
то открывается меню, причем ширина элементов меню равна 100%.
CSS
nav[role="custom-dropdown"] label {
position: relative;
display: block;
width: 100%;
}
nav[role="custom-dropdown"] label:after {
position: absolute;
content: "\2261";
}
nav[role="custom-dropdown"] input[type=checkbox]:checked ~ ul {
display: block;
}
nav[role="custom-dropdown"] input[type=checkbox]:checked ~ ul > li {
width: 100%;
}
nav[role="custom-dropdown"] input[type=checkbox]:checked ~ ul > li:after {
position: absolute;
content: "\203A";
}
}
В закрытом состоянии:
В открытом состоянии:
Преимущества:
- Не занимает много места в закрытом состоянии
- Не используется javascript
- Элементы полностью стилизуются
Недостатки:
- Плохая семантика (input/html)
- Дополнительный HTML
Canvas
Базовая идея та же: на экранах с маленьким разрешением скрываем основное меню и вместо него показываем элементы
input
и
label
(как их использовать смотрите в пункте 3 и checkbox hack). Когда пользователь кликает по
label
, основное меню "выплывает" с левой стороны , а контент смещается вправо.
HTML
<input type="checkbox" id="menu">
<label for="menu" onclick></label>
<!-- basic menu goes here -->
<div class="content">
<!-- content goes here -->
</div>
На больших экранах скрываем label:
CSS
label {
position: absolute;
left: 0;
display: none;
}
На маленьких экранах мы прячем основное меня за пределами окна браузера и показываем
label
/
input
. Скрытие происходит за счет абсолютного позиционирования и отрицательного значения для свойства
left
. Чтобы помочь пользователю опознать меню, добавим псевдоэлемент с текстом = (в качестве значения для
content
будем использовать код “
\2261
”). Когда пользователь кликает по
label
, отрицательное значение у свойства
left
блока с меню обнуляется, за счет чего меню выдвигается вправо и одновременно с этим смещаем контент при помощи правого поля.
CSS
@media screen and (max-width: 44em) {
.four {
margin: 0;
overflow-x: hidden;
}
nav[role="off-canvas"] {
left: -20em;
width: 20em;
}
nav[role="off-canvas"] ul > li {
width: 100%;
}
label {
display: block;
}
label:after {
position: absolute;
content: "\2261";
}
input:checked ~ nav[role="off-canvas"] {
left: 0;
}
input:checked ~ nav[role="off-canvas"] ul > li:after {
position: absolute;
right: .25em;
content: "\203A";
}
input:checked ~ .content {
margin-left: 20.5em;
margin-right: -20.5em;
}
}
На маленьких экранах в закрытом состоянии:
На маленьких экранах в открытом состоянии:
Преимущества:
- Не занимает много места в закрытом состоянии
- Не используется javascript
- Элементы полностью стилизуются
- Договоренность с Facebook / Google+ app
Недостатки:
- Плохая семантика (input/html)
- Дополнительный HTML
- Абсолютное позиционирование относительно body практически идентично фиксированному положению.
Все техники, описанные выше, имеют одну цель: создать адаптивное меню для современных браузеров. Ну и так как ни на одном мобильном устройстве вы не найдете IE 8 и ниже, то вам не о чем беспокоиться.
По материалам статьи адаптивное меню, концепция
Комментарии к статье
плохо работает все примеры