Кількісний порядок в CSS

19

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

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

Ви можете відразу припустити, що JavaScript тут підійде найкраще – просто зробити цикл по всім елементам, і якщо їх більше трьох, то застосувати необхідні стилі. А що якщо я скажу, що ви могли б зробити те ж саме на чистому CSS?

Лічильник на чистому CSS

Останнім часом я повністю занурився в flexbox, викладаючи його разом з обтіканням контенту за допомогою властивості float. Дані методи ми використовували у верстці нашого маленького проекту HackerYou. І я виявив, що студенти швидко схоплюють цю тему. У специфікації flexbox є властивості, що дозволяють змінювати розмітку новими способами. Один з цих способів це властивість order, воно дозволяє змінювати візуальний порядок контенту, не чіпаючи при цьому його розмітку.

У сукупності з медіа запитами order вкрай корисна річ, нам відкривається можливість змінювати порядок контенту в залежності від розміру вікна браузера. І це змусило мене замислитися: Чому ми не можемо змінювати порядок елементів в залежності від кількості контенту?

Кількісні запити

Ідея, запропонована Lea Verou, André Luis і Heydon Pickering, полягає в тому, що ці запити підраховують число суміжних елементів і застосовують стилі до них, якщо набирається певна їх кількість. Що якщо ми комбінуємо кількісні запити з властивістю order, щоб змінити порядок контенту в залежності від його кількості?

Спосіб на основі Flexbox

Flexbox або «Flexible Box Layout Module» це CSS специфікація, що дозволяє гнучко маніпулювати контентом в осередках сітки і легко підганяти розмір клітинок під розміри батьків. Вперше представлений в 2009 році за все це час flexbox зазнав масу змін. Тим не менш, він підтримується у всіх останніх версіях браузерів крім IE9+.

Одним з найбільш значущих змін у flexbox став синтаксис присвоєння імен асоціативних властивостей і значень. Оскільки специфікація розвивається протягом усього часу, виробники браузерів будуть використовувати той синтаксис, який доступний на даний момент часу. Тому для підтримки застарілих браузерів необхідно використовувати вендорные префікси.

Один з рекомендованих інструментів для забезпечення кроссбраузерного CSS коду це Autoprefixer, як правило, він уже включений у препроцессоры, Gulp і Grunt файли.

Як зрозуміти суть порядку

Перш ніж зануритися в кількісні запити і розбиратися в їх роботі, необхідно зрозуміти, як працювати з властивістю order. Спочатку необхідно обернути контент батьківським елементом і додати до цього блоку-обгортці стилі display:flex.

HTML код:

Hello

World!

І CSS код:

.container {
display: flex;
}

За промовчанням елементи вишиковуються в порядку, заданому розміткою. Всі дочірні елементи в батьківському flexbox мають значення order рівне 1.

Дане значення не має одиниці виміру і просто зіставляється з порядковим номером елемента відносно інших елементів навколо нього. Але ми можемо змінити значення окремого елемента за допомогою властивості order.

p.itemOne {
order: 2;
}

У наведеному вище прикладі ми змінили порядок рядка p.itemOne на значення 2, і цей рядок тепер відображається після p.itemTwo. Тим самим ми змінюємо візуальне представлення елементів для користувача. Зверніть увагу на те, що розмітка залишилася колишньою.

Лічильники на CSS

Медіа запити, так? Настільки відмінний інструмент CSS в окремих випадках. Такими випадками можуть виступати тип пристрою, розмір екрана, колір і т. д. – доволі-таки потужна штука. Але дані запити застосовуються тільки до пристрою користувача; немає певного способу CSS, який обчислює кількість контенту в елементі.

Якщо поставитися до справи творчо і уважніше розглянути існуючі CSS псевдокласи, ми можемо створити інструментарій для підрахунку кількості дочірніх елементів і застосування відповідних стилів до них. Наприклад, давайте скористаємося звичайним нумерованим списком:

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Вся магія за підрахунком суміжних елементів у коді нижче. Дані стилі застосовуються до елементів, якщо їх 4 або більше.

ul.ellist li:nth-last-child(n+4) ~ li,
ul.ellist li:nth-last-child(n+4):first-child {
// тут прописані стилі
}

Стоп, не може бути!

Точно, це саме той селектор. На російську мову можна перекласти як: «Коли дочірніх елементів у списку 4 або більше, отримуємо елементи іншого списку разом з першим дочірнім елементом». Розберемо докладніше. Для початку почнемо з лічильника:

ul.ellist li:nth-last-child(n+4) {
// Стилі!
}

Перекладається як «Дойди до останнього дочірнього елемента і відрахуй тому 4 елемента». Стилі застосовуються до четвертого елементу і всім, хто перед ним. (Відлік ведеться у зворотному порядку!). Продовжимо і поекспериментуємо з кодом, призначимо селекторам інші значення.

Ось такі лічильники. Якщо суміжних елементів менше чотирьох, стилі не будуть застосовані. Тепер ми змінимо цей селектор, щоб він обирав всі li зі списку за допомогою універсального селектора.

ul.ellist li:nth-last-child(n+4) ~ li {
// Стилі!
}

Вся проблема в тому, що в такому разі не вибирається перший дочірній елемент. Ми можемо додати ще одні селектор:

ul.ellist li:nth-last-child(n+4) ~ li,
ul.ellist li:nth-last-child(n+4):first-child {
// Стилі!
}

Звичайно, ми можемо зробити селектор більш незалежним, просто вказавши батьківський елемент і дозволивши йому вибрати всі дочірні елементи. Ми зробимо це за допомогою селектора *.

element > *:nth-last-child(n+4) ~ *,
element *:nth-last-child(n+4):first-child {
// Стилі!
}

Порядок на основі кількості елементів

Тепер, коли ми розібралися, як підраховувати елементи за допомогою CSS і як використовувати flexbox для зміни порядку контенту, давайте об’єднаємо їх і створимо інструментарій для упорядкування елементів на основі їх кількості.

Ще раз, ми хочемо зробити останній елемент третім у списку (тобто щоб той відповідав останнім у першій рядку), якщо елементів більше трьох.

Додамо пару стилів. До контейнера-батькові додамо display:flex, це властивість дозволить нам застосувати властивість order до його дочірніх елементів. Крім того, щоб відрізняти елементи один від одного ми додамо пару стилів за замовчуванням до елементу .target.

ul.ellist {
margin: 0 20px;
padding: 0;
list-style: none;
display: flex;
flex-flow: row wrap;
}
ul.ellist > * {
border: 10px solid #27ae60;
text-align: center;
flex: 1 0 calc(33.33% — 20px);
padding: 20px;
margin: 10px;
}
.target {
color: white;
background: #2980b9;
border: 10px solid #3498db;
}
ul.ellist, ul.ellist > * {
box-sizing: border-box;
}
ul.ellist {
margin: 0 20px;
padding: 0;
list-style: none;
display: flex;
flex-flow: row wrap;
}
ul.ellist > * {
border: 10px solid #27ae60;
text-align: center;
flex: 1 0 calc(33.33% — 20px);
padding: 20px;
margin: 10px;
}
ul.ellist .target {
color: white;
background: #2980b9;
border: 10px solid #3498db;
}

Тепер, коли у нас є базові стилі, ми можемо створити логіку для упорядкування елементів певним чином. Ще раз, за замовчуванням усі елементи мають значення order рівне 1 і відображаються в тому порядку, в якому вони прописані у верстці. За допомогою кількісних запитів ми можемо підрахувати кількість елементів. Більше їх, ніж три елементи.

ul.ellist > *:nth-last-child(n+3) {
// Стилі!
}

Потім, якщо умова здійснилось, ми можемо вибрати необхідний елемент .target. Ми застосували значення -1 властивості order, тепер цей елемент відобразиться на початку списку.

ul.ellist > *:nth-last-child(n+3) ~ .target {
order: -1;
}

Вуаля! Ми тільки що стилізували елемент, підрахувавши кількість суміжних з ним елементів. За допомогою цього коду ми можемо ставити один елемент перед іншим. А що якщо необхідно поставити елемент між двома?

Трохи логічних роздумів

Перед нами завдання з трьома невідомими:

За замовчуванням усі елементи списку мають значення order:1. Нам необхідно зробити так, щоб це значення не змінилося у перших двох елементів.

Наш особливий елемент повинен розташовуватися в кінці першого рядка. Отже, нам необхідно збільшити значення order і зробити його більше, ніж у перших двох елементів, тобто 2.

Всі елементи, починаючи з третього, повинні мати значення order вище, ніж у нашого цільового елемента. Значить, для інших елементів значення order буде дорівнювати 3.

Як вам? Так як всі елементи мають значення 1, то нам не потрібно буде її оголошувати. Давайте встановимо нашому особливому елементу значення order:2 з допомогою кількісних запитів, ефективно помістивши його після всіх.

ul.ellist > *:nth-last-child(n+3) ~ .target {
order: 2;
}

Потім, застосувавши інший кількісний запит nth-child(), ми почнемо вважати елементи з початку списку, а не з кінця. Так як раніше ми прописали запит .target, то цей елемент буде проігноровано, проте всі інші третій і наступні за ним елементи змінюють свій порядок.

ul.ellist > *:nth-last-child(n+3) ~ .target {
order: 2;
}
ul.ellist > *:nth-child(n+3) {
order: 3;
}

Давайте розберемо ще раз!

Ми ведемо відлік з кінця списку за дочірнім елементів на предмет збігу з певною кількістю. Якщо кількість елементів задовольняє умові, ми застосовуємо стилі до виділеного нами елементів. Потім ми ведемо відлік з початку списку і застосовуємо стилі до всіх елементів за певним, особливим елементом. Найголовніша особливість в тому, що якщо ми видалимо елементи, то цільовий елемент залишиться на потрібному нам місці.

  • 1
  • 2
  • 3
  • 4

Кінцева завдання

Першою думкою, коли я ставив перед собою цю задачу, було використовувати мови програмування. Так як я використав WordPress, я міг би змінити цикл і, визначивши кількість елементів, вставити в потрібному місці цільової елемент.
Але так як я створював сайт для школи з front-end розробці, я хотів зробити це на чистому CSS і розкрити можливості властивості flexbox order. Нижче приклад кінцевого результату, виконаного цілком на CSS.

Застосування на практиці

SASS

Концепція кількісних запитів досить нова, і в зв’язку з цим написання селекторів може бути трохи важко. Тим не менш, співтовариство розробників гаряче прийняла цю концепцію і вже пише Sass mixin’и, які допоможуть нам робити запити набагато ефективніше. Такі бібліотеки, як, наприклад, бібліотека Quantity Queries Mixin від Daniel Guillan дозволяє нам писати медіа запити, як просте підключення.

@include at least($count) { … }
@include between($first, $last) { … }

Також дана концепція і міць, прихована в ній, пояснюються в безлічі статей. James Steinbach написав чудову статтю «Застосування Sass в кількісних запитах».

POSTCSS

PostCSS – новий інструмент для зміни CSS за допомогою JavaScript. На даний момент флора і фауна PostCSS налічує безліч розроблених співтовариством плагінів, включаючи Quantity Query плагін. Даний плагін дозволяє налаштовувати псевдокласи на значення в певному діапазоні.

p:at least(4) { … }
p:between(4,6) { … }

Підтримка браузерами

На даний момент CSS псевдокласи і flexbox чудово працюють в сучасних браузерах. Якщо ваш проект враховує користувачів не нижче ніж IE10, ви можете використовувати кількісні запити разом з flexbox.

Де використовувати

При створенні сайтів ми часто вдаємося до мов програмування, які надають нам можливість підраховувати і модифікувати наш контент, якщо це необхідно. Однак CSS став набагато краще, і ми пішли від мов програмування в бік просунутих властивостей CSS.

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

Кількісне упорядкування дозволяє нам видалити шматки коду з циклами, які відповідали за підрахунок і вставлення елементів в правильному порядку, приводячи наш контент до семантично чистому вигляді.

Чудовим прикладом користі кількісного упорядкування буде сайт новин з рекламою. В розмітці всі статті йдуть по порядку, а блок реклами розташований у самому кінці. З точки зору доступності такий підхід надає нам безперервний потік контенту. При використанні кількісного впорядкування реклама може бути розміщена в будь-якому місці і лише на рівні подання.

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

Висновок

Кількісні запити і впорядкування – передові концепції і можуть налякати новачків. Тим не менш, чим далі ми відкладаємо стилізацію подання від мов програмування в бік CSS, тим більше ми будемо використовувати даний інструментарій. Все більша кількість членів нашої спільноти відкривають для себе контент запити, і тепер ми можемо використовувати кількісні запити для зміни порядку контенту просто за допомогою лічильників.