Введение
В коде, представленном в статье, я не использую браузерные префиксы, чтобы код стилей оставался простым к прочтению и пониманию. В более сложных примерах испольуется SCSS. Каждый из примеров размещен на сайте CodePen, где вы можете увидеть скомпилированный CSS.
Все подходы в этой статье используют простой HTML код, который я называю «базовое меню». Атрибут role используется чтобы указать определенный тип: горизонтальное меню (full-horizontal), выпадающий список (select), ниспадающее меню (custom-dropdown) и 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 screen and (max-width: 44em) { }
1. Горизонтальное меню
Самый простой подход, потому что вам нужно лишь сделать список элементов шириной во всю страницу:
<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>
@media screen and (max-width: 44em) { nav[role="full-horizontal"] { ul > li { width: 100%; } } }
С дополнительным оформлением так оно выглядит на экранах с небольшим разрешением:
Преимущества
- Не требуется JavaScript
- Никакой лишней разметки
- Простой код стилей
Недостатки
- Занимает слишком много места на экране
Пример горизонтального меню можно увидеть на сайте CodePen.
2. Выпадающий список
В данном подходе скрывается базовое меню и показывается выпадающий список вместо него.
Чтобы добиться такого эффекта нам нужно добавить в базовую разметку выпадающий список. Чтобы он работал нам придется добавить JavaScript код, который изменяет значение window.location.href когда происходит событие onchange
<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>
Скрываем список на больших экранах:
nav[role="select"] { > select { display:none; } }
На маленьких экранах скрываем базовое меню и показываем выпадающий список. Чтобы помочь пользователю понять, что это меню — мы добавим псевдо-элемент с тектом «Меню»
@media screen and (max-width: 44em) { nav[role="select"] { ul { display: none; } select { display: block; width: 100%; } &:after { position: absolute; content: "Menu"; right: 0; bottom: -1em; } } }
С дополнительным оформлением так оно выглядит на экранах с небольшим разрешением:
Преимущества
- Не занимает много места
- Использует «собственные» элементы управления
Недостатки
- Для работы требуется JavaScript
- Происходит дублирование контента
- Выпадающий список не удается стилизовать во всех браузерах
3. Пользовательское ниспадающее меню
В данном подходе на небольших экранах скрывается базовое меню и показывается input и label вместо них (используется хак с чекбоксом). Когда пользователь кликает на label, базовое меню показывается под ним.
<nav role="custom-dropdown"> <!-- Advanced Checkbox Hack (see description below) --> <!-- basic menu goes here --> </nav>
Проблемы с использованием хака с чекбоксом
Две основных проблемы с этим решением:
- Оно не работает на мобильных версиях Safari (iOS < 6.0). Невозможно кликнуть на label в браузере под iOS < 6.0, чтобы сработал input из-за бага. Решается добавлением пустого события onclick на label
- Оно не работает на основном браузере ОС Android версии меньше или равной 4.1.2. Давным давно был баг в WebKit движке, который не позволял использовать псевдо-классы с комбинацией селекторов
+
и~
h1 ~ p { color: black; } h1:hover ~ p { color: red; }
Это не оказывало никакого эффекта, потому что хак с чекбоксом использовал псевдокласс :checked
с селектором ~
. И пока баг не был исправлен в WebKit 535.1 (Chrome 13) и в актуальном для Android 4.1.2 WebKit 534.30, хак не работал ни на каком устройстве с ОС Android.
Лучшее решение — это использовать анимацию только для WebKit-браузеров для тега <body>
Комбинация всех вариантов создает расширенный хак для чекбоксов:
<!-- Fix for iOS --> <input type="checkbox" id="menu"> <label for="menu" onclick></label>
/* 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:
nav[role="custom-dropdown"] { label { display: none; } }
Для небольших экранов мы скрываем базовое меню и показываем label. Чтобы помочь пользователю понять, чтобы это меню, мы добавим псевдоэлемент с текстом "≡" в label (представим в виде кода "\2261", чтобы использовать как содержимое псевдоэлемента). Когда пользователь кликает на input, базовое меню показывается и список элементов раскрывается во всю ширину.
@media screen and (max-width: 44em) { nav[role="custom-dropdown"] { ul { display: none; height: 100%; } label { position: relative; display: block; width: 100%; } label:after { position: absolute; content: "\2261"; } input:checked ~ ul { display: block; > li { width: 100%; } } } }
Так меню выглядит на маленьких экранах:
Преимущества
- Не занимает много места в закрытом состоянии
- Целиком стилизуется
- Не требует JavaScript
Недостатки
- Не семантичный код (input / label)
- Требуется дополнительный HTML
4. Canvas
В этом подходе, на небольших экранах, скрывается базовое меню и показывается input и label как в варианте 3. Когда пользователь кликает на label, базовое меню выплывает слева и содержимое перемещается вправа. Экран разделяется на части в пропорциях 80% меню и 20% содержимое (в зависимости от разрешения и единиц, используемых в CSS)
<input type="checkbox" id="menu"> <label for="menu" onclick></label> <!-- basic menu goes here --> <div class="content"> <!-- content goes here --> </div>
На больших экранах мы скрываем label.
label { position: absolute; left: 0; display: none; }
На маленьких экранах мы помешаем меню вне содержимого окна и показываем label и input. Чтобы скрыть меню мы устанавливаем для него ширину и отрицательное значение положения. Чтобы помочь пользователю понять, чтобы это меню, мы так же добавим псевдоэлемент с текстом "≡" в label (в виде кода "\2261", чтобы использовать как содержимое псевдоэлемента).
@media screen and (max-width: 44em) { $menu_width: 20em; body { overflow-x: hidden; } nav[role="off-canvas"] { position: absolute; left: -$menu_width; width: $menu_width; ul > li { width: 100%; } } label { display: block; } label:after { position: absolute; content: "\2261"; } input:checked ~ nav[role="off-canvas"] { left: 0; } input:checked ~ .content { margin-left: $menu_width + .5em; margin-right: -($menu_width + .5em); } }
С дополнительным оформлением так оно выглядит на экранах с небольшим разрешением:
Преимущества
- Не занимает много места в закрытом состоянии
- Целиком стилизуется
- Не требует JavaScript
- Работает как Facebook / Google+ приложения
Недостатки
- Не семантичный код (input / label)
- Требуется дополнительный HTML
- Абсолютное позиционирование элемента body вызывает ощущение зафиксированного положения
Работает ли это под IE?
Все использованные техники преследуют одну цель: создать адаптивное меню для современных браузеров! И все потому, что нит никаких IE8 или ниже ни на каких мобильных устройствах и, поэтому, мы можем совершенно не беспокоится об этом вопросе.
ссылка на оригинал статьи http://habrahabr.ru/post/159359/
Добавить комментарий