Золоті правила з написання чистого CSS

17

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

Золоті правила з написання чистого CSS

намагайтеся не вживати глобальні і елементні селектори;

не використовувати надмірно специфічні селектори;

використовуйте семантичні імена класів;

не прив’язуйте сильно CSS до розмітки.

Розберемо кожне правило.

Намагайтеся не вживати глобальні селектори

До глобальних селекторам відноситься універсальний селектор (*), елементні селектори типу p, button і h1, а також селектори атрибутів типу [type=checkbox]. Стилі в таких селекторах застосовуються до всіх елементів на сайті. Приклад:

button {
background: #FFC107;
border: 1px outset #FF9800;
display: block;
font: bold 16px / 1.5 sans-serif;
margin: 1rem auto;
width: 50%;
padding: .5rem;
}

Начебто все добре. А що, якщо нам знадобиться кнопка з іншими стилями? Давайте стилізуємо кнопку .close, яка буде закривати діалогові вікна:

Close

Замітка: чому не dialog?

Ми взяли section замість dialog, так як підтримка dialog обмежена Blink браузерами типу Chrome/Chromium, Opera і Yandex.

Тепер потрібно переписати всі рядки CSS, які не повинні успадковуватися від селектора button:

.close {
background: #e00;
border: 2px solid #fff;
color: #fff;
display: inline-block;
margin: 0;
font-size: 12px;
font-weight: normal;
line-height: 1;
padding: 5px;
border-radius: 100px;
width: auto;
}

Для перезапису значень за замовчуванням у браузері нам все ще потрібні ці оголошення. А якщо обмежити стилі button в клас .default? Тоді ми зможемо викинути властивості display, font-weight, line-height, margin, padding і width з класу .close. Розмір скоротиться на 23%:

.default {
background: #FFC107;
border: 1px outset #FF9800;
display: block;
font: bold 16px / 1.5 sans-serif;
margin: 1rem auto;
width: 50%;
padding: .5rem;
}
.close {
background: #e00;
border: 2px solid #fff;
color: #fff;
font-size: 12px;
padding: 5px;
border-radius: 100px;
}

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

Глобальні стилі і селектори відмінно підходять для переустановки і нормалізації стилів в браузері за замовчуванням. У більшості інших випадків вони засмічують код.

Не використовувати надмірно специфічні селектори

Збереження низької специфічності селекторів – один із способів створення легковажного, повторно використовуваного та обслуговуваного CSS. Наскільки ви пам’ятаєте, типізовані селектори мають специфічність 0,01. У класів специфічність дорівнює 0,1,0:

/* Специфічність 0,0,1 */
p {
color: #222;
font-size: 12px;
}
/* Специфічність 0,1,0 */
.error {
color: #a00;
}

Стилі в класі мають більш високий пріоритет, ніж правила звичайного типізованого селектора. Як доповнювати і об’єднувати клас з типізованих селектором не потрібно. Це підвищує специфічність селектора, що, в свою чергу, збільшує вагу файлу.

Тобто запис виду p.error це те ж саме, що й просто .error. Також з плюсів те, що .error можна використовувати повторно на інших елементах. Селектор p.error обмежує клас .error тільки на тегах p.

Не сцепляйте класи

Уникайте зчеплення класів. Селектори .message.warning мають специфічність 0,2,0. Селектори з більш високою специфічністю складніше переписати. Також зчіпка часто викликає сторонні ефекти. Приклад:

message {
background: #eee;
border: 2px solid #333;
border-radius: 1em;
padding: 1em;
}
.message.error {
background: #f30;
color: #fff;
}
.error {
background: #ff0;
border-color: #fc0;
}

Тег

і CSS дають нам прекрасний сірий блок з темно-сірою рамкою (див. Малюнок 2.1):

Золоті правила з написання чистого CSS

Рисунок 2.1 візуальний ефект нашого селектора .message

А тег

дає нам фон .message.error і рамку .error (див. Малюнок 2.2):

Золоті правила з написання чистого CSS

Малюнок 2.2. візуальний ефект селектора .message.error

Єдиний спосіб переписати селектор з зчеплених класів – це використовувати селектор з ще більшою специфічністю. Щоб позбутися від жовтої рамки, нам довелося б підчепити ще один клас або тип: .message.warning.exception або div.message.warning. Легше створити новий клас. Якщо помітили, що у вас є зчеплені селектори, поверніться на початок. Або недоліки в самому дизайні, або ви передчасно намагаєтесь запобігти проблеми, яких немає. Поправте все. Так ви позбавите себе від головного болю і зможете повторно використовувати свій код, воно того варто.

Намагайтеся не використовувати селектори id

Правила з селектором id складно перепризначити, так як id можна призначити тільки одного елемента на сторінці. Як правило, в таких випадках використовується список селекторів id, наприклад: #sidebar-features та #sidebar-sports.

Ідентифікатори мають високу специфічність, щоб їх переписати, потрібен ще більш довгий селектор. У коді нижче щоб переписати фоновий колір #sidebar, необхідно використовувати #sidebar.sports і #sidebar.local:

#sidebar {
float: right;
width: 25%;
background: #eee;
}
#sidebar.sports {
background: #d5e3ff;
}
#sidebar.local {
background: #ffcccc;
}

Якщо ж використовувати класи, наприклад, .sidebar, то це спрощує зчеплення селекторів:

sidebar {
float: right;
width: 25%;
background: #eee;
}
.sports {
background: #d5e3ff;
}
.local {
background: #ffcccc;
}

Крім економії пари байт наші класи .sports і .local тепер можна використовувати на інших елементах.

Селектори атрибутів типу [id=sidebar] дозволяють обійти високу специфічність ідентифікаторів. Цей селектор не можна використовувати повторно, як клас, зате низька специфічність дозволяє не використовувати зчеплення.

Примітка: коли висока специфічність id буває корисна

У певних обставинах може знадобитися висока специфічність id селектора. Наприклад, мережа медіа сайтів може використовувати одну панелі навігації у всіх своїх властивостях. Цей компонент повинен бути однаковим на всіх сайтах в мережі, і його стилі не повинні легко змінюватися. Селектор id знижує ризик випадкової перезапису стилів.

Ну і нарешті, давайте поговоримо про селектори типу #main article.sports table#stats tr:nth-child(even) td:last-child. Такі селектори не тільки дуже довгі, з-за своєї специфічності 2,3,4 їх не можна використовувати повторно. Скільки елементів розмітки підійде під такий селектор? Давайте спростимо його. Його відразу ж можна обрізати #stats tr:nth-child(even) td:last-child. Все одно селектор надто специфічний. Набагато краще (як з причин повторного використання, так і мінімізації розміру) – використовувати клас.

Замітка: ознака вкладення препроцессоре

Занадто велика специфічність селекторів найчастіше є результатом глибокій вкладеності в препроцессоре.

Використовуйте семантичні імена класів

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

Приклад того, як не можна робити: .red-text, .blue-button, .border-4px, .margin10px. Що тут не так? Ці класи дуже сильно прив’язані до варіантів дизайну. Повідомлення про помилку можна розмітити за допомогою class=»red-text». А що якщо дизайн зміниться, і текст про помилку стане чорним всередині помаранчевого блоку? Тоді ваш клас буде неточний, що викличе труднощі в розумінні коду у вас і ваших колег.

У такому випадку краще використовувати класи .alert, .error або .message-error. Ці класи показують, для чого вони призначені, а також повідомляють про тип контенту (повідомлення про помилку), до якого вони застосовуються. Щоб показати, що класи належать до макету, додайте префікс layout-, grid-, col — або просто l-. У розділі про методології БЕМ описується цей процес.

Не прив’язуйте сильно CSS до розмітки

Можливо, ви використовували в своєму коді дочірні та батьківські селектори. Дочірні селектори підпорядковуються шаблоном E > F, де F – елемент, а E – прямий батько. Наприклад, article > h1 підходить під h1 в запису

Advanced CSS

, але не підходить під h1 в запису

Advanced CSS

. Батьківський селектор навпаки підпорядковується шаблоном E F, де F – елемент, а E – дочірній елемент. У попередньому прикладі селектор article h1 вибере h1 в обох випадках.

Ні дочірні, ні батьківські селектори не є чимось поганим. Вони добре обмежують область застосування CSS правил. Але вони далеко не ідеальні. Розмітка час від часу змінюється.

Підніміть руку, якщо наступна історія про вас. Ви розробили кілька шаблонів для клієнта. В CSS є дочірні та батьківські селектори в парі місць. Велика їх частина є також елементними селекторами, тобто селектори типу .promo > h2 і .media h3 розкидані по всьому коду. Ваш клієнт найняв SEO-консультанта, який подивився вашу розмітку і запропонував вам замінити h2 і h3 на h1 і h2. Проблема в тому, що вам доведеться міняти ще і CSS.

У селекторів класів є перевага. Запис форми .promo > .headline або .media .title (або ще простіше .promo-headline і .media-title) дозволяє змінити розмітку без зміни CSS.

Для використання такого правила необхідний доступ до розмітки. При роботі зі старої CMS, доступу може не бути. У таких випадках можна використовувати дочірні, батьківські і селектори псевдокласів.

Примітка: більш архітектурні CSS правила

Philip Walton розповідає про ці та інші правила в своїй статті CSS архітектура. Також для поповнення знань з CSS архітектурі рекомендую відвідати сайт Harry Roberts CSS Guidelines і прочитати пост Nicolas Gallagher про HTML семантику і front-end архітектуру.

Далі ми розглянемо дві методології CSS архітектури. Обидва методу створені для прискорення процесу розробки великих сайтів у великих командах. Вони також добре підходять для команди з однієї людини.