Чуйна гумова навігація з різною кількістю пунктів на CSS

24

Від автора: Близько 6 місяців тому мене попросили створити однострочную навігаційну панель, яка буде розтягуватися на всю ширину контейнера, але при цьому кількість пунктів в ній може змінюватися. Кількість пунктів меню було зазначено в іншому місці і, швидше за все, могло змінитися в майбутньому.

Подумавши наперед, я вирішив, що було б нераціонально змінювати CSS всякий раз, коли потрібно додати або видалити один з пунктів меню. Потрібно було знайти відповідне рішення, і, в ідеалі, без застосування JavaScript.

Задаємо ширину у відсотках

Якщо пункти меню будуть фіксованої ширини, то вони не зможуть рівномірно і повністю заповнити чуйний контейнер, як показано на рисунку.

Чуйна гумова навігація з різною кількістю пунктів на CSS

Тому нам потрібно використовувати відсотки, щоб домогтися потрібного результату. Використання відсотків — це поширений спосіб створення гумової сітки макета в чуйну дизайні, і він нам теж тут стане в нагоді. Наприклад, розглянемо наступний звичний HTML-код:

  • Головна
  • Про нас
  • Послуги
  • Продукція
  • Вакансії
  • Контакти

І ми додамо наступний 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 встановлено властивість width: 100%, щоб він повністю заповнив весь доступний простір.

Елементами li задані дві властивості, які відповідають за ширину: width: calc(100% / 6); width: 16.6667%;. Завдяки цьому елементи меню трощаться всередині елемента nav на 6 рівних частин. Тут важливий порядок проходження даних властивостей, тобто це дозволить браузерами, підтримує властивість calc() використовувати саме його замість стандартного відсоткового значення для ширини. Браузери, які не підтримують властивість calc(), будуть просто ігнорувати його і використовувати альтернативний варіант. Я звик використовувати властивість calc() з відсотками, щоб підвищити читаність коду і дозволити браузеру використовувати оптимізований результат. Таким чином, я вже не турбуюся про зазначення повторюваних дробових значень.

Властивість box-sizing: border-box; встановлено для елементів li. Це змушує властивість width включити значення властивостей border-left border-right у загальне значення ширини. Без вказівки даного властивості елементи li не будуть поміщатися всередині елемента nav, і останній елемент li буде перенесено на новий рядок. Багато воліють призначати властивість box-sizing: border-box; для всіх елементів, щоб було легше керувати їхньою шириною (рекомендація Підлоги Айриша (Paul Irish).

Результат додавання цих стилів показаний на сайті CodePen:

Відкрийте його у новому вікні і протестуйте на чуйність. Необхідний вид отримано, і він є гумовим.

Якщо ми додамо або приберемо пункти меню?

Ось що станеться, якщо ми приберемо один з пунктів меню, залишивши при цьому колишній CSS-код:

Як бачите, тепер праворуч, на місці віддаленого пункту, утворилося порожній простір. А що якщо замість цього, навпаки, додати ще один пункт меню?

Тепер останній пункт меню перескакує на другий рядок. Очевидно, що все це не відповідає нашим вимогам. Для вирішення цієї задачі можна використовувати JavaScript, який порахує число пунктів меню, визначить їх процентне співвідношення і в циклі присвоїть значення ширини елементів li. Однак, я завжди неохоче використовую JavaScript для відображення макета, якщо тільки немає ніякого іншого варіанту. Більш того, тоді б це не була стаття про CSS, якщо б я збирався описати рішення на JavaScript! Повертаємося до вирішення нашої задачі…

(Нове) знайомство з табличним макетом

Не бійтеся, я не закликаю вас повертатися до використання табличної HTML-верстки в дусі 90-х. Звичайно ж, це було б семантично неправильно. Однак, існують значення властивості display, які дозволяють елементам вести себе, як таблиці. Це означає, що колишня HTML-структура може бути використана разом з наступним 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 з потрібним значенням ми, по суті, перетворюємо елемент nav в таблицю, елемент ul – в рядок, а елемент li – у комірку таблиці. Зверніть увагу, що ми також оголосили властивість table-layout: fixed, яке встановлює однакову ширину для кожного пункту меню. Його можна і видалити, але зміна довжини тексту у пунктів меню може призвести до того, що таблиця буде виглядати не вирівняною, тому дійте обережно. Ось посилання на демо-приклад з кнопками, які дозволять вам додавати/видаляти пункти меню:

Можливо, це не ідеальне рішення (прошу вибачення у ненависників таблиць), зате це просте рішення, яке працює. Браузерна підтримка теж хороша.

Майбутнє: модуль Flexbox

Модуль Flexbox є головним претендентом на те, щоб замінити використовуване тут рішення, коли старими версіями браузера Internet Explorer перестануть користуватися, і браузерна підтримка модуля Flexbox буде ставати все краще і краще. Якщо ви не знайомі з модулем Flexbox, то ви можете ознайомитися з нещодавно опублікованою статтею на сайті SitePoint або перейти до розділу зі специфікацією, яка дає Flexbox наступне пояснення:

У моделі «гумового» макета, дочірні елементи «гумового» контейнера можуть бути розташовані в будь-якому напрямку, і їх розміри можуть бути змінені, або в більшу сторону, щоб заповнити невикористовуване простір, або в меншу сторону, щоб уникнути виходу за межі його батьківського елементу. Також можна легко управляти як горизонтальним, так і вертикальним вирівнюванням дочірніх елементів.

Звучить чудово щодо вирішення нашої задачі. І знову ми можемо використовувати той же HTML, а для реалізації підходу 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;
}

Зверніть увагу на наступні властивості Flexbox:

display: flex; – це властивість застосовується до елемента ul і дозволяє створити «гнучке» оточення для всіх дочірніх елементів.

flex-direction: row; – це властивість застосовується до елемента ul для того щоб дочірні елементи шикувалися зліва направо. Правда, це значення за замовчуванням, тому воно не так обов’язково.

flex-grow: 1; – це магічне властивість, яка рівномірно розподіляє всі елементи li всередині контейнера. Якби вам потрібно було задати конкретного елемента li значення 2, тоді цей елемент став би вдвічі більше порівняно з іншими елементами.

У модуля Flexbox є кілька цікавих можливостей, які можуть бути корисними в інших ситуаціях. Наприклад, можливість, яка дозволяє змінити послідовність пунктів меню за допомогою властивості order. Подивіться кінцевий результат із застосуванням Flexbox:

Як бачите, ми досягли такого ж результату. І знову ви можете використати кнопки, щоб поекспериментувати з додаванням/видаленням одного пункту меню. Ви також можете додати більше пунктів меню, змінивши HTML-код. Змінюючи ширину вікна браузера, можна протестувати «гумовість» макета.