Кілька CSS методів щодо зміни візуального порядку

2

Від автора: у цьому уроці ми розберемо кілька CSS методів щодо зміни порядку HTML-елементів.

Наша мета

Ми хочемо побудувати дуже простий макет, особливо на маленьких екранах (т. е. <600px). Ось так він буде виглядати:

На середніх і великих екранах (тобто вище або дорівнює 600px) макет повинен бути таким:

Найбільш складне завдання – знайти спосіб перевернути порядок кнопок.

Розмітка

Розмітка буде дуже проста, звичайний div з чотирма кнопками всередині:

Button 1
Button 2
Button 3
Button 4

Базові стилі

На маленьких екранах у всіх кнопок загальні стилі:

.boxes button {
display: block;
width: 100%;
padding: 15px;
border: none;
margin-bottom: 5px;
box-sizing: border-box;
font-size: 1rem;
text-align: center;
text-decoration: none;
background: gold;
color: #000;
}
.boxes button:nth-of-type(even) {
background: #e6c200;
}

На великих екранах ми лише додамо до кнопок властивість width: 25%. Інші стилі будуть додаватися в залежності від CSS методу, який ми використовуємо для інверсії порядку кнопок.

@media screen and (min-width: 600px) {
/* в методах з flexbox і сіткою ми пропускаємо це властивість */
width: 25%;
/* тут код */
}

Залишилося додати стилі кнопок в стані focus:

.boxes button:focus {
outline: none;
color: #fff;
background: firebrick;
}

Якщо за допомогою клавіші Tab переміщатися по кнопок, кнопка з фокусом змінить колір на темно-червоний.

Методи зі зміною порядку колонок

Тепер ми готові протестувати кілька способів щодо зміни порядку кнопок на екранах шириною більше 599px.

Метод №1: обтікання

Один з найшвидших способів додати кнопок праве обтікання. Додатковий CSS код:

@media screen and (min-width: 600px) {
.boxes button {
float: right;
width: 25%;
}
}

Метод №2: позиціонування

Можна встановити елементи, відносно або абсолютно. У першому випадку ми зрушуємо всі кнопки вліво за допомогою властивості position: relative і за допомогою властивості left вибудовуємо їх в ряд.Для цього нам потрібен наступний CSS код:

@media screen and (min-width: 600px) {
.boxes button {
position: relative;
float: left;
width: 25%;
}
.boxes button:nth-of-type(1) {
left: 75%;
}
.boxes button:nth-of-type(2) {
left: 25%;
}
.boxes button:nth-of-type(3) {
left: -25%;
}
.boxes button:nth-of-type(4) {
left: -75%;
}
}

У другому випадку кнопок можна було б задати властивість position: absolute і з допомогою властивості left більш точно налаштувати їх позиціонування.

@media screen and (min-width: 600px) {
.boxes {
position: relative;
}
.boxes button {
position: absolute;
width: 25%;
}
.boxes button:nth-of-type(1) {
left: 75%;
}
.boxes button:nth-of-type(2) {
left: 50%;
}
.boxes button:nth-of-type(3) {
left: 25%;
}
.boxes button:nth-of-type(4) {
left: 0;
}
}

Метод №3: властивість direction

Менш очевидний спосіб – властивість direction. Зазвичай, в такому випадку резервується деякий простір під розгорнутий текст. У нашому випадку ми задаємо властивість direction: rtl (справа наліво) контейнера, що миттєво змінює порядок елементів у макеті. Зверніть увагу: у цьому прикладі елементів задається поведінка клітинок таблиці для того, щоб вибудувати їх в один ряд.

@media screen and (min-width: 600px) {
.boxes {
display: table;
width: 100%;
direction: rtl;
}
.boxes button {
display: table cell;
width: 25%;
}
}

Також варто сказати, що якщо з якихось причин нам захочеться змінити напрямок тексту кнопок, можна використати спеціальне правило:

.boxes button {
unicode-bidi: bidi-override;
}

Метод №4: трансформації

Витончений метод. Кнопкам необхідно додати ліве обтікання і властивість transform: scaleX(-1). Також дана властивість необхідно прописати для батьківського блоку. Від’ємне значення не збільшує елементи. Насправді, вони просто відображаються по горизонтальній осі.

@media screen and (min-width: 600px) {
.boxes {
transform: scaleX(-1);
}
.boxes button {
float: left;
transform: scaleX(-1);
width: 25%;
}
}

Для досягнення потрібного ефекту можна навіть використовувати функцію трансформації rotate. Потрібно всього лише додати властивість transform: rotateY(180deg) до кнопок і батьківського блоку.

@media screen and (min-width: 600px) {
.boxes {
transform: rotateY(180deg);
}
.boxes button {
float: left;
transform: rotateY(180deg);
width: 25%;
}
}

Метод №5: flexbox

Змінити порядок колонок можна і з допомогою flexbox. В нашому випадку ми можемо скористатися двома властивостями flexbox для досягнення необхідного ефекту. У першому випадку батьківський блок кнопок необхідно перетворити в флекс контейнер і додати до нього властивість flex-direction: row-reverse.

@media screen and (min-width: 600px) {
.boxes {
display: flex;
flex-direction: row-reverse;
}
}

Другий спосіб – перетворити батьківський блок в флекс контейнер і з допомогою властивість order задавати порядок кнопок.

@media screen and (min-width: 600px) {
.boxes {
display: flex;
}
.boxes button:nth-of-type(1) {
order: 4;
}
.boxes button:nth-of-type(2) {
order: 3;
}
.boxes button:nth-of-type(3) {
order: 2;
}
.boxes button:nth-of-type(4) {
order: 1;
}
}

Метод №6: CSS сітка

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

Не вдаючись у деталі, давайте розберемо два способи. Перший спосіб – перетворити батьківський блок в grid-контейнер і з допомогою властивості grid-column задавати порядок розташування кнопок. Також ми додамо властивість grid-row: 1, щоб всі кнопки були на одному ряду.

@media screen and (min-width: 600px) {
.boxes {
display: grid;
grid-template-columns: repeat(4, 1fr);
}
.boxes button {
grid-row: 1;
}
.boxes button:nth-of-type(1) {
grid-column: 4;
}
.boxes button:nth-of-type(2) {
grid-column: 3;
}
.boxes button:nth-of-type(3) {
grid-column: 2;
}
.boxes button:nth-of-type(4) {
grid-column: 1;
}
}

Другий спосіб з сітками схожий на другий спосіб з flexbox. Необхідно перетворити батьківський блок в grid-контейнер і з допомогою властивості order задавати порядок відображення кнопок.

@media screen and (min-width: 600px) {
.boxes {
display: grid;
grid-template-columns: repeat(4, 1fr);
}
.boxes button:nth-of-type(1) {
order: 4;
}
.boxes button:nth-of-type(2) {
order: 3;
}
.boxes button:nth-of-type(3) {
order: 2;
}
.boxes button:nth-of-type(4) {
order: 1;
}
}

Дана демо працює тільки з включеним прапором «Experimental Web Platform features» в Chrome.

Вихідний порядок або візуальний порядок

Ми показали, що змінити порядок кнопок можна CSS різними способами. Давайте ще раз глянемо на всі демо, і за допомогою клавіатури пройдемося по кнопках (за допомогою клавіші Tab). Ви помітите, що навіть якщо кнопка 4 візуально варто першої, то першою отримає фокус кнопка 1, так як вона є першою в DOM. Те ж саме буде, якщо протестувати демо скрін рідерах (я тестував в NVDA).

Враховуючи різницю між порядком в DOM, CSS, необхідно вкрай обережно працювати з частинами сайту, які були перебудовані за допомогою CSS. Приміром, flexbox властивість order одне з найбільш гнучких для зміни порядку відображення елементів, однак у специфікації говориться: «Редактори повинні використовувати властивість order тільки для візуального, не логічного зміни порядку контенту. Стилі, в яких властивість order використовується для логічного зміни порядку, неприйнятні.»

Те ж саме говориться в специфікації і про властивість order в сітках: «При зміні порядку флекс елементів властивість order повинно використовуватися тільки у випадках, коли візуальний порядок не повинен збігатися з порядком читання тексту скрін рідерами та порядком меню. В іншому випадку документ повинен бути перебудований.»

Зверніть увагу: якщо ви тестували другий спосіб з flexbox в браузері Firefox, ви могли помітити, що навігація з клавіатури працює, але на середніх екранах перший фокус отримує кнопка 4. Це баг.

Висновок

У цьому уроці ми розглянули різні CSS методи щодо зміни порядку відображення HTML-елементів. Не всі методи підходять на всі випадки. Перед вибором слід врахувати:

Які браузери ви будете підтримувати. Приміром, деякі з вищезазначених способів не працюють в старих версіях IE (<10).

Складність перестроювання. Перестроювання буде простим, як у наших прикладах, або щось складніше?

Якщо ви знаєте інші методи щодо зміни порядку кнопок, пишіть про них у коментарях.