Отзывчивая навигация на CSS, число пунктов неизвестно
Несколько месяцев назад меня попросили разработать простую навигационную панель, которая должна содержать разное количество пунктов меню, а ширина должна быть резиновой и быть равной ширине контейнера-родителя. Количество навигационных элементов неизвестно, задается на стороне и, вероятно, поменяется в будущем.
Размышляя наперед, я пришел к выводу, что было бы непрактично изменять CSS каждый раз, когда потребуется добавить или удалить пункт меню. Также в идеале решение должно быть без javascript.
Используем проценты для ширины
Пункты с фиксированной шириной не в состоянии полностью заполнить родительский контейнер, что и проиллюстрировано ниже:

Итак, чтобы растянуть пункты на всю ширину нам потребуются проценты.
Проценты являются распространенным методом, чтобы создать резиновую сетку в отзывчивом дизайне.
Например, рассмотрим следующую HTML-разметку:
HTML
<nav>
<ul>
<li><a href="/home.html">Home</a></li>
<li><a href="/about.html">About</a></li>
<li><a href="/services.html">Services</a></li>
<li><a href="/products.html">Products</a></li>
<li><a href="/jobs.html">Jobs</a></li>
<li><a href="/contact.html">Contact</a></li>
</ul>
</nav>
И следующий CSS:
CSS
nav {
width: 100%;
background: #f0f0f0;
border: 1px solid #ccc;
border-right: none;
}
nav ul {
overflow: hidden;
margin: 0;
padding: 0;
}
nav ul li {
list-style: none;
float: left;
text-align: center;
border-left: 1px solid #fff;
border-right: 1px solid #ccc;
width: 16.6667%; /* fallback for non-calc() browsers */
width: calc(100% / 6);
box-sizing: border-box;
}
nav ul li:first-child {
border-left: none;
}
nav ul li a {
display: block;
text-decoration: none;
color: #616161;
padding: 10px 0;
}
- Элементу nav задана
100%
ширина, чтобы заполнить все возможное пространство элемента-родителя. - У элемента
li
задано два свойства с шириной -width: calc(100% / 6);
иwidth: 16.6667%;
. Этим мы размещаем пункты меню в элементе nav, как шесть равных блоков. Свойстваwidth
важно установить в правильном порядке, чтобы те браузеры, которые поддерживаютcalc()
могли его использовать. Я предпочитаю использоватьcalc()
с процентами это повышает читаемость кода и позволяет браузеру использовать оптимальный вариант. box-sizing: border-box;
задана у элементовli.
В этом случае в ширину включаютсяborder-left
иborder-right
. Без использования этого объявления, элементыli
не впишутся внутри элемента nav и последнийli
сместится на новую строку вниз.
Результат от используемых стилей можно увидеть ниже:
See the Pen Резиновая навигация by dnzl ( @dnzl ) on CodePen .
Откройте код в новом окне и протестируйте его на отзывчивость. Желаемый вид достигнут плюс меню отзывчиво.
Что если мы удалим или добавим пункты в меню?
Во что будет, если мы удалим один пункт меню из навигации:
See the Pen Резиновая навигация, удаляем 1 пункт (число пунктов фиксированно) by dnzl ( @dnzl ) on CodePen .
Как вы можете видеть, справа образовалось пустое пространство, на том месте, где был расположен последний пункт меню.
Что будет, если добавить один пункт меню?
See the Pen Резиновая навигация, добавляем 1 пункт (число пунктов фиксированно) by dnzl ( @dnzl ) on CodePen .
Сейчас последний пункт меню переместился на вторую строку.
Без паники, я не собираюсь возвращаться в 90-е, чтобы использовать таблицу для макета, это семантически неверно, конечно. Однако, есть значения у свойства display
, позволяющие элементу вести себя и выглядеть наподобие таблицы.
Это означает, что вышеприведенный html-код может быть использован со следующим CSS:
CSS
nav {
display: table;
table-layout: fixed;
width: 100%;
}
nav ul {
display: table-row;
margin: 0;
padding: 0;
}
nav ul li {
list-style: none;
display: table-cell;
text-align: center;
}
nav ul li a {
display: block;
}
Настройки свойства display
позволяют элементу na vбыть таблицей, элементу ul
- строкой, li
– ячейкой таблицы. Отметьте включение объявления table-layout: fixed
, благодаря которому пункты меню принимают равную ширину. Его можно удалить, но колебания длины текста может нарушить внешний вид таблицы, поэтому подойдите к этому с осторожностью.
Взгляните на demo, с помощью кнопок добавьте или удалите элементы у навигационной панели.
See the Pen Резиновая навигация с использованием display: table by dnzl ( @dnzl ) on CodePen .
Будущее: flexbox
Flexbox является основным кандидатом на замену вышеприведенного метода. Особенно с учетом вывода из обращения старых версий браузера IE и всевозрастающей поддержкой flexbox в современных браузерах. Если вы не знакомы с flexbox, то можете почитать следующие материалы:
- (Полное руководство по Flexbox)
- www.sitepoint.com/are-we-ready-to-use-flexbox/
- www.w3.org/TR/css3-flexbox/
Главная задумка flex-вёрстки в наделении контейнера способностью изменять ширину/высоту (и порядок) своих элементов для наилучшего заполнения пространства (в большинстве случаев — для поддержки всех видов дисплеев и размеров экранов).
Звучит идеально для решения моей проблемы.
Снова воспользуемся нашим HTML и создадим CSS-стили на основе flexbox.
CSS
nav {
width: 100%;
}
nav ul {
display: flex;
flex-direction: row;
margin: 0;
padding: 0;
}
nav ul li {
list-style: none;
flex-grow: 1;
text-align: center;
}
nav ul li a {
display: block;
}
-
display: flex;
применяется к элементуul
и позволяет подключить гибкую среду для его детей. -
flex-direction: row;
применяется к элементуul
и тем самым позиционирует его детей в формате слева направо (определяя направление для flex-элементов). Это значение по умолчанию, так что обозначать его явно необходимости нет. -
flex-grow: 1;
это магия, которая делает дочерние элементы тегаul
равными по ширине. Если вы укажете конкретномуli
значение 2, то этот элемент будет увеличен ровно в 2 раза относительно других элементов.
Flexbox имеет множество интересных особенностей, которые могут быть уместны в зависимости от ситуаций.
Ниже финальный пример построенный на использовании flexbox.
See the Pen Резиновая навигация с использованием Flexbox by dnzl ( @dnzl ) on CodePen .
Как вы можете видеть, достигается тот же результат, что и с табличным макетом. Снова протестируйте пример, добавляя или удаляя новые пункты, используя соответствующие кнопки. Поменяйте размеры окна браузера и обратите внимание на отзывчивость.
Если у вас есть свое решение для создания отзывчивой навигации оставляйте комментарии.
Источник
Комментарии к статье
Спасибо, не мог понять что всё дело во "flex-grow: 1;"