Справочник фронт-энд девелопера: виды горизонтальных панелей навигации

5a756b5cad98c93d62d06b513dbd6e17
Предисловие: работая верстальщиком, ваш покорный слуга заметил, что существует несколько типов меню; при этом для верстки каждого из них следует использовать свои приемы.
Подробности — под катом.

Данная статья нацелена скорее на начинающих верстальщиков, но, может быть, матерые профессионалы тоже найдут в ней что-то новое или будут обращаться к ней как к справочнику.
Топик структурирован следующим образом: сначала ставится задача — описывается вид требуемого навигационного блока, затем рассматриваются приемы, позволяющие создать именно такую навигацию.
Подразумевается, что написание стилей ведется под семантически корректную структуру меню, которая выглядит примерно так:

<nav>
  <ul>
    <li><a href="index.html">Домой</a></li>
    <li><a href="shop.html">Сделать заказ</a></li>
    <li><a href="contacts.html">Обратная связь</a></li>
  </ul>
</nav>

При верстке под doctype, отличный от html5, элемент nav опускаем или заменяем на соответствующий div.

Что ж, начнем!..

Пункты меню, расположенные по правой/левой стороне

В данном разделе рассмотрены навигационные блоки, в которых элементы размещены по правой/левой стороне. Для верстки таких блоков, в зависимости от ситуации, можно использовать несколько способов:

  1. display: inline;
  2. float: left/right;
  3. display: inline-block.
Display: inline

Когда применяем
Данный способ целесообразно применять при верстке меню простого вида, в котором элементы представлены в виде отдельных слов, не имея padding’ов и разделены лишь пробелами между ними:
4f755f88b56e5ea586d7a76ee9b898de

Живой пример

Как делается
У элементов li в CSS нужно установить свойство display: inline. Кстати, это уберет и ненужные в большинстве меню такого вида маркеры, так как они находятся в дополнительных блоках, которые содержатся у элементов с display: list-item, а у inline’ов отсутствуют.
У ul устанавливаем свойство text-align в значение right или left соответсвенно.

Примечания

  • При использовании этого варианта стоит помнить, что у inline элементов вертикальные margin’ы не учитываются, но горизонтальные работают;
  • при необходимости верстки pixel perfect, есть вероятность столкновения с проблемой: в разных браузерах ширина пробела между элементами разная. Для решения проблемы расстояние между элементами выставляют margin’ами, апробелы убирают;
  • если подчеркивание в ссылках элементов меню сделать нижним border’ом, в современных браузерах можно получить красивое анимированное на :hover меню (JSFiddle).
Float: left/right

Когда применяем
Когда необходимо сделать меню с элементами, имеющими padding’и и/или фиксированную высоту/ширину:
43c5ec4f0807d9771ca688fb11634483

Живой пример
Таким способом сверстано верхнее меню НЛО; более наглядный пример — Themeforest:
b0b2939564aea0110091e4000f7589ae

Как делается
Устанавливаем float: left или float:right элементам li. Если нужно убрать маркеры, нужно добавить display: block или list-style: none.

Примечания

  • Необходимо «очистить» ul, задав ему класс .clearfix или поместив в его конец элемент с clear: both, иначе у ul высота будет равна нулю; о других способах «очистки» float’ов можно прочитать здесь;
  • пример интересного меню, сверстанного float’ами: html5guy.
Display: inline-block

Когда применяем
Задачи те же, что и при верстке с float. И да, при решении такой задачи inline-block пал в неравном бою. Во-первых, кроссбраузерность такого решения ниже, чем у float’a, а во-вторых, между inline-block’ами, как и между inline-элементами, появляются пробелы, зачастую ненужные. Эти проблемы решаемы, но зачем их создавать?

Как делается
Устанавливаем display: inline-block элементам li. Ну, а для IE7 (если вы его поддерживаете) прописываем *display:inline; *zoom: 1.

Симметричные относительно левой и правой сторон блоки навигации

В данном разделе рассмотрены навигационные блоки, расположенные симметрично. Существует несколько видов таких меню; каждому из них соответствует свой способ верстки:

  1. пункты меню выровнены по центру;
  2. пункты меню равномерно распределены по всей ширине, между элементами имеется промежуток;
  3. пункты меню равномерно распределены по всей ширине, элементы заполняют всю ширину ul.
Пункты меню выровнены по центру

Когда применяем
Меню расположено по центру:
6f70aa84abf99ad11acffb372a951876

6f5dc20447c75dd8363e4b3dc5da6ea3

Живой пример

Как делается
В зависимости от вида пунктов меню, устанавливаем display: inline или display: inline-block (если для пунктов меню предусмотрены padding’и задана ширина и/или высота) элементам li. Родителю (ul) устанавливаем text-align: center.

Примечания
Позволю себе повториться: иногда появляется необходимость в том, чтобы убрать пробелы между inline- и inline-block- элементами; 7 способов того, как это сделать, можно найти здесь.

Пункты меню равномерно распределены по всей ширине, между элементами имеется промежуток

Когда применяем
Пункты меню равномерно распределены по всей ширине, между отдельными пунктами имеются промежутки:
1995190fb2d7bc566f9940d412b44528

5181ccdfb5d5c3cfc0e65af49e80667c

Живой пример
К сожалению, меню такого типа найти не удалось, поэтому здесь — пример с JSFiddle.
fbeaa50223bdc7135c831fa983e4f423

Как делается
В зависимости от вида пунктов меню, устанавливаем display: inline или display: inline-block элементам li. Родителю (ul) устанавливаем text-align: justify. Но сразу justify не заработает — нужно переполнить первую строку (если непонятно почему так — запускаем ворд и пытаемся растянуть несколько слов на всю ширину при помощи justify). Поэтому в конец элемента ul добавляем дополнительный элемент с display: inline-block и width: 100%, или, что лучше, псевдо-элемент ::after с такими же характеристиками.

Примечания
Помните, в предыдущих типах меню мы убирали пробелы между элементами со свойством display, установленным в inline и inline-block? Так вот, в этом случае так делать категорически нельзя — браузеру нужны промежутки между пунктами меню. Кстати, если убрать пробелы между некоторыми элементами, можно группировать кнопки (JSFiddle):
c070d79ba337064c2e0d51d9b1b22dad

Пункты меню равномерно распределены по всей ширине, элементы заполняют всю ширину ul.

Когда применяем
Между пунктами меню нет промежутков, любое количество пунктов меню занимает всю ширину:
695a9496f7f82bf93ea1c2c843a40ff6

Живой пример
Apple.com:
e71475ef3c6cc3ed32b4e0a87ece39d0

Пример подобного меню на JSFiddle можно потрогать здесь.

Как делается
При решении данной задачи есть соблазн сверстать меню таблицами; но мы же не собираемся нарушать семантику документа, правда? Поэтому используем display: table-cell для li и display: table для ul; потом задаем ширину для ul
Если нужна поддержка старых браузеров, используем скрипт-полифилл, подменяющий такие блоки на таблицы для IE6 и IE7 или организуем fallback другими способами.

Примечания
При верстке меню данным способом нужно помнить, что нельзя размещать элементы с position: absolute относительно table-cell.

Почему?
Дело в том, что в спецификации w3c действие position: relative на table-cell не определено, поэтому в каждом браузере могут наблюдаться свои особенности.
Посмотрите этот пример в разных браузерах (особо пристально смотрим на поведение Mozilla Firefox!).
843d157f4c728beb89c497c68edc6639
Для решения этой проблемы в ячейку нужно помещать div, относительно которого производить позиционирование.

Итог

В статье перечислены основные виды меню и особенности их верстки. Надеюсь, этот материал пригодится вам, спасибо за внимание.