Angular IDPStrong Junior
Модулі / Розмітка й стилі / Каскад і специфічність
🔥 0

Модуль 1 · урок 8 з 14

Каскад і специфічність

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

Як рахується вага селектора

Специфічність — це трійка чисел (A, B, C). Порівнюються зліва направо, як версія програми: якщо A більше — далі можна не дивитись.

ТРІЙКА СПЕЦИФІЧНОСТІ A — #id кожен id +1 B — .class [attr] :hover класи, атрибути, псевдокласи C — div ::before теги й псевдоелементи .btn (0, 1, 0) .card .btn (0, 2, 0) ← вже перебиває .btn button.btn:hover (0, 2, 1) #app .btn (1, 1, 0) ← один id б'є будь-яку кількість класів :where(.card) .btn (0, 1, 0) ← :where() обнуляє вагу того, що всередині
Порівняння йде порозрядно: один #id сильніший за десять класів. Тому «важкі» селектори з id — головна причина, через яку далі доводиться писати !important.

Порядок правил у каскаді

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

  1. Чи збігся селектор узагалі.
  2. Шар каскаду (@layer), якщо використовується.
  3. !important — перевертає все з ніг на голову.
  4. Специфічність (A, B, C).
  5. Порядок у файлі: хто пізніше, той і правий.

Як писати так, щоб не воювати з каскадом

Робочі правила
  • Один клас — один компонент: .card, .card__title.
  • Селектор завглибшки максимум два рівні.
  • Модифікатор — теж клас: .btn--ghost, а не .panel .btn.
  • Для стилів «за замовчуванням» — :where(), щоб їх легко перебивати.
  • Порядок файлів: спершу базове, потім компоненти, потім утиліти.
Що породжує !important
  • Стилі по #id.
  • Ланцюги .a .b .c .d з вкладеності SCSS.
  • Інлайн-стилі з шаблону.
  • Перебивання чужої бібліотеки «зверху» замість налаштування її токенів.
  • Утиліти, підключені раніше за компоненти.

:is(), :where() і @layer

/* :is() групує й бере НАЙБІЛЬШУ вагу зі списку */
:is(h1, h2, h3) .lead { }      /* = (0,1,0) + вага найважчого в дужках */

/* :where() групує, але його власна вага = 0 */
:where(.prose) p { margin-block: 1em; }  /* (0,0,1) — перебити зможе навіть .p */

/* @layer задає пріоритет груп; шар, оголошений пізніше, сильніший */
@layer base, components, utilities;

@layer base       { button { font: inherit; } }
@layer components { .btn { padding: 8px 14px; } }
@layer utilities  { .mt-0 { margin-top: 0; } }   /* переможе .btn, хоч вага однакова */

Практично: :where() — для скидань і базових стилів, які завжди мають легко перебиватись. @layer — коли в проєкті є і своя бібліотека, і утиліти, і треба раз і назавжди зафіксувати, хто кого перебиває.

Що казати про !important на рев'ю

Якщо колись доведеться його поставити (а в чужих віджетах доводиться), правильна формула: «тут !important, бо стиль приходить інлайном зі сторонньої бібліотеки, і перебити його інакше не можна». Це технічна причина. А от «інакше не працювало» — це не причина, і саме так це почує лід.

≈ 45 хв · +25 XP за урок