Об’єктноорієнтований CSS: чому елементарні правки призводять до несподіваних наслідків та як із цим боротися
Усі статті, обговорення, новини про Front-end — в одному місці. Підписуйтеся на телеграм-канал!
Я — Євгеній Вінійчук, у розробці вже понад 7 років. У компанії Youshido виріс від Trainee до Lead Front-end Developer. Створював сайти та застосунки як для стартапів, так і для бізнес-гігантів — Viasat, Jacobs, Pepsi, Tuborg тощо. Зараз працюю Senior Frontend Developer в ІТ-компанії ButterflyMX. У цьому матеріалі розкажу про те, чому об’єктноорієнтований підхід є невіддільною частиною написання CSS та як розбивання сторінки на блоки полегшує роботу ІТ-спеціалісту, а користування ресурсом — читачеві сайту.
Раптовий злам програми — одна з найбільш поширених проблем розробників-початківців. Часом мінімальні зміни призводять до несподіваних наслідків. Змінивши вигляд сторінки профілю користувача, можна нашкодити відображенню коментарів на іншій сторінці. Зменшити ймовірність виникнення такої ситуації дозволяє об’єктноорієнтований CSS (OOCSS) — методологія, що розглядає елементи сторінки як незалежні будівельні блоки.
Значна частина проблем стається через відсутність структури та стратегії під час розв’язання задачі. Розгляньмо типовий приклад рішення «в лоб». Нехай нам потрібно зверстати сторінку. Починаємо з «шапки», де є кнопка «Sign In»:
Для її стилізації можна написати щось на кшталт такого:
#header .button { background: black; color: white; margin-left: 10px; padding: 5px; border: 2px solid transparent; border-radius: 20px; }
Продовжуючи працювати над сторінкою, натрапляємо на блок, де зустрічаємо вже знайому кнопку:
Оскільки кнопка в блоці Get out, тоді логічним буде:
#get-out .button { color: black; padding: 0 10px; border: 2px solid black; border-radius: 20px; margin-top: 20px }
Цей код буде працювати, проте виникають такі питання:
— А якщо така кнопка потрібна ще на декількох сторінках?
— А якщо усім кнопкам такого типу треба, наприклад, поміняти поля?
Не відповівши на ці фундаментальні питання з самого початку, згодом отримаємо помилки в місцях, де точно їх не очікували. Такий код стає сплутаним, а його підтримка ускладнюється. Ось один із реальних прикладів того, як виглядатиме код без структури з часом (зверніть увагу на рівень вкладеності класу .icon):
Приклад заплутаного коду, який писався без попереднього аналізу структури
Щоб покращити можливості масштабування та зменшити рівень складності, пропонується методологія OOCSS. В її основі лежать наступні ідеї.
Розділення структурних та стильових характеристик елементів
Цей принцип про те, що стильові характеристики елемента (колір, фон, рамка тощо) мають описуватися окремо від розмірних характеристик (ширина/висота/поля тощо). У такий спосіб ми налаштовуємо каркас елемента, а потім одягаємо поверх нього різні «вбрання». Це дозволяє уникнути дублювання коду та повторно використовувати елемент, додаючи йому нового функціоналу разом із появою нових потреб.
Розглянемо приклад проблеми та її розв’язання:
.button-green { padding: 0 20px; height: 42px; text-align: center; color: green; border: 1px solid green; border-radius: 20px; } .button-red { padding: 0 20px; height: 42px; text-align: center; color: red; border: 1px solid red; border-radius: 20px; }
Вище ми описали дві кнопки. В цьому випадку, щоб змінити загальну характеристику для всіх кнопок (наприклад, поля), нам потрібно модифікувати кожен клас. Тобто зараз маємо ситуацію, коли елементи, який мають спільну характеристику, існують окремо як повністю незлагоджені. Якщо використати правило про розділення структури та зовнішнього вигляду, матимемо наступне:
.button { padding: 0 20px; height: 42px; text-align: center; border-radius: 20px; } .button-green { border: 1px solid green; border-radius: 20px; } .button-red { color: red; border: 1px solid red; }
Тепер ми розділили структуру від стилізації. До того ж чітко простежується, що кнопки успадковують спільні характеристики від «материнської», не виникає питання «міняючи поля зеленої кнопки, чи повинні змінитися поля червоної?».
Розділення на структурні та контентні елементи
Згідно з методологією, контентними елементами виступають параграфи, зображення, кнопки та інші, що вкладають в структурні елементи (контейнери). Ідея полягає в тому, що стилізація контентних елементів має не залежати від батьківського елемента. Тобто намагатися писати стилі контентних елементів без залежності від того, в якому контейнері вони лежать.
Розглянемо приклад проблеми та її вирішення:
#header { background: #fcfcfc; } #header .nav { padding: 0 20px; } #header .nav .nav-item { color: #000000; font-size: 14px; font-weight: 500; margin: 0 20px; }
У цьому прикладі ми стилізували навігацію та її елементи в «шапці» сторінки. Нехай, нам потрібна така ж навігація також в футері. Як бути тоді? Нашвидкуруч можемо зробити щось таке:
#header { background: #fcfcfc; } #header .nav, #footer .nav { padding: 0 20px; } #header .nav .nav-item #footer .nav .nav-item { color: #000000; font-size: 14px; font-weight: 500; margin: 0 20px; } #footer { background: #000000; } #footer .nav .nav-item { color: #ffffff }
Задачу вирішено, але маємо декілька проблем. По-перше, це продубльовані стилі для хедера та футера. По-друге, навігація виявилась тісно зв’язана із контейнером, в якому знаходиться, що унеможливлює її використання поза його межами. Такі стилі буде важко масштабувати з ростом проєкту через надмірну зв’язність. Покращмо це рішення, відділивши контейнери (хедер та футер) від контенту (навігації):
#header { background: #fcfcfc; } #footer { background: #000000; } .nav { padding: 0 20px; } .nav-item { font-size: 14px; font-weight: 500; } .nav-item-white { color: #ffffff; } .nav-item-black { color: #000000; }
Код вище дозволяє використовувати елементи навігації незалежно від того, де саме вони будуть розташовані. До того ж ми використали перше правило про розділення структури елементів та його зображення. Цей код значно легше підтримувати завдяки зменшеному рівню складності.
Переваги OOCSS
Структурованість
Використання OOCSS спонукає спочатку проаналізувати весь дизайн та виділити функціональні елементи, поставити собі питання «В яких станах ці елементи можуть перебувати?» та розробити елементи, з яких потім будувати додаток. Тобто ми фокусуємося на конкретних елементах, приділяючи їм більше уваги в певний момент часу та розв’язуємо задачу комплексно.
Низька зв’язність
Завдяки розділенню відповідальності, елементи залежать один від одного лише структурно (наприклад, кнопці налаштовують відступ відносно її контейнера, коли ставлять поруч з іншими блоками). Це дозволяє легко замінити один елемент на інший та повторно використовувати блоки незалежно від розташування.
Завдяки вищенаведеним перевагам, слідування правилам OOCSS зменшує кількість помилок та покращується масштабованість коду. Його легше читати, що підвищує ймовірність того, що розробники зрозуміють код однаково. Окрім того, це полегшує інтеграцію нових розробників в проєкт.
А що далі?
OOCSS допомагає розділяти відповідальність, але він не диктує чітких правил щодо структури коду. Тому дуже раджу звернути увагу на методологію BEM (block, element, modifier), яка продовжує ідею OOCSS та дає чіткі поради з неймінгу та структури. Вона є однією із найуживаніших та є невіддільною частиною в багатьох компаніях.
Використання об’єктноорієнтованого підходу до CSS буде корисним усім розробникам, оскільки це є базою до структурування коду. Модульна система ізолює блоки, робить код більш масштабованим і дозволяє уникати типових CSS-проблем.
27 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів