Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке каскад у CSS». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Каскад у CSS** - це алгоритм, який вирішує конфлікти між CSS-правилами, що застосовуються до одного елемента. Порядок: походження > важливість (`!important`) > специфічність > порядок у коді. Клас перемагає тег, `!important` перемагає inline-стиль, пізніше правило виграє лише при рівній специфічності. **Головне:** каскад вибирає переможця для кожної властивості окремо, а не для всього правила.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Каскад у CSS** - це алгоритм, який браузер використовує для вирішення конфліктів: коли кілька CSS-правил застосовуються до одного елемента, каскад вибирає переможне значення для кожної властивості окремо. ## Теорія ### TL;DR - Каскад вибирає **одне значення для кожної властивості** з усіх відповідних правил, а не одне "переможне" правило повністю. - Порядок: Походження > Важливість > Специфічність > Порядок у коді. - `!important` змінює пріоритет усередині кожного рівня походження, але не скасовує специфічність повністю. - Пізніше правило виграє лише при рівній специфічності. - Правило може програти по `color` і при цьому виграти по `font-size` на тому самому елементі. ### Швидкий приклад ```html <style> p { color: blue; } /* програє: нижча специфічність */ .highlight { color: red; } /* виграє: клас перемагає тег */ </style> <p class="highlight">Цей текст червоний.</p> <!-- red --> <p>Цей текст синій.</p> <!-- blue --> ``` Обидва правила підходять для першого `<p>`. Каскад вибирає `.highlight` для `color`, бо клас (специфічність 0,0,1,0) перемагає тег (0,0,0,1). Конфлікту по інших властивостях немає, тому вони не змінюються. ### Як каскад вирішує конфлікти Браузер сортує всі відповідні декларації за таким порядком: 1. **Походження і важливість.** Стилі браузера (user-agent) мають найнижчий пріоритет. Твої авторські стилі стоять вище. Стилі користувача з розширень браузера або налаштувань ОС - ще вище. `!important` перевертає кожен рівень: author `!important` перемагає звичайний author, user `!important` перемагає майже все. 2. **Специфічність (specificity).** Рахується як чотиричастинний кортеж: inline (1,0,0,0), ID (0,1,0,0), класи і атрибути і псевдокласи (0,0,1,0), теги і псевдоелементи (0,0,0,1). Порівнюй зліва направо. `#header a` (0,1,0,1) перемагає `.menu a` (0,0,1,1), бо ID-колонка вирішує одразу. 3. **Порядок у коді.** Якщо все решта рівне, перемагає декларація, яка стоїть останньою в документі. ### Ключова ідея, яку часто не розуміють Каскад не вибирає одне правило і не ігнорує решту. Він вибирає переможне значення **для кожної властивості окремо**. Правило з `color: red; font-size: 16px` може програти по `color` іншому правилу і при цьому внести `font-size` у підсумковий стиль. Саме на цьому злитті більшість розробників плутаються, бо очікують що одне правило "захопить" елемент повністю. ### Коли що використовувати - **Простий сайт без конфліктів** - тримай специфічність низькою і покладайся на порядок у коді. - **Конфлікти з бібліотекою компонентів** - підніми специфічність через BEM-селектори типу `.card__button--primary` замість `!important`. - **Боротьба з чужим CSS** - `!important` як крайній засіб, не як перший хід. Inline-стилі в такому разі кращий короткостроковий варіант. - **Система тем** - шаруй таблиці стилів: базова, потім тема, потім налаштування користувача. CSS `@layer` (підтримується у всіх основних браузерах з 2022 року) робить цей підхід явним. - **Відлагодження дивних стилів** - відкрий панель "Styles" у DevTools. Там видно кожну декларацію, яка перемогла, і чому решта перекреслені. ### Як браузер обробляє це всередині Blink (движок Chrome) парсить усі таблиці стилів у дерево каскаду, відсортоване за походженням. Під час layout браузер знаходить відповідні селектори для кожного елемента, рахує специфічність і проходить дерево. Найвища комбінація походження/важливості/специфічності/порядку виграє для кожної властивості. Значення без конфліктів зливаються в об'єкт підсумкового стилю. Саме цей крок злиття описаний у специфікації, але більшість туторіалів його пропускають. ### Типові помилки - **Вважати, що пізніше правило завжди перемагає** ```css p { color: red; } /* стоїть першим, але виграє */ div p { color: blue; } /* стоїть пізніше, але програє */ ``` `div p` має специфічність 0,0,0,2, а `p` - лише 0,0,0,1. Специфічність перемагає порядок. - **Використовувати `!important` як швидкий фікс** Я бачив команди, які місяцями воювали з `!important`, бо один розробник додав його до спільного компонента і тепер ніхто не міг нічого перевизначити нормально. ```css .btn { color: black !important; } /* тема тепер не може це змінити */ ``` Фікс: підніми специфічність. `.theme-dark .btn { color: white; }` вирішить питання без отруєння всього далі по ланцюжку. - **Думати, що inline-стилі завжди виграють** ```html <p style="color: blue" class="override">Текст</p> <style>.override { color: red !important; }</style> <!-- Результат: red --> ``` `!important` перемагає inline-стилі. Лише `style="color: blue !important"` поверне inline-значення. - **Ігнорувати стилі користувача** Розширення браузера вставляють CSS з рівня user-origin, який автоматично перевизначає твої авторські стилі. Якщо щось виглядає зламаним у браузері користувача, але у тебе все нормально - перевір розширення. DevTools дозволяє емулювати user stylesheet для тестування. ### Де зустрічається у реальних проектах - **Tailwind CSS** - утилітарні класи типу `bg-red-500` перемагають базові стилі за специфічністю або порядком. Властивості без конфліктів з базових стилів при цьому застосовуються. - **Bootstrap** - `.btn-primary` (клас плюс тег) перевизначає загальний `.btn`. - **Styled Components / Emotion** - генерує ізольовані класи, але каскад все одно працює між різними бібліотеками на одній сторінці. - **Material UI** - CSS custom properties разом із каскадом обробляють перевизначення теми на рівні окремих властивостей. ### Питання на співбесіді **Q:** Який повний порядок у каскаді? **A:** Спочатку походження і важливість (user-agent < user < author, `!important` перевертає кожен рівень), потім специфічність (inline > ID > клас/атрибут/псевдоклас > тег), потім порядок у коді. **Q:** Як рахується специфічність? **A:** Чотиричастинний кортеж (A, B, C, D): A дорівнює 1 для inline, B рахує ID, C рахує класи і атрибути і псевдокласи, D рахує теги і псевдоелементи. Порівнюй зліва направо. Комбінатори типу `>` і `+` нічого не додають. **Q:** Що відбувається при рівній специфічності? **A:** Для звичайних правил перемагає останнє в документі. Для `!important` навпаки: перемагає перше. **Q:** Чи працює каскад так само всередині Shadow DOM? **A:** Ні. Shadow DOM інкапсулює власний каскад. Конструйовані таблиці стилів (adopted sheets, Chrome 101+) зливаються в тіньовий каскад без впливу на light DOM. Inline-стилі на host-елементі при цьому перемагають `!important` у тіньових стилях, що часто дивує розробників Web Components. **Q:** Як CSS Custom Properties взаємодіють із каскадом? **A:** Кастомні властивості каскадують як будь-яка інша декларація. `--color: red` виграє за звичайними правилами каскаду. Підстановка `color: var(--color)` відбувається після того, як каскад вирішив значення змінної, а не до. ## Приклади ### Конфлікт специфічності зі злиттям властивостей ```html <!DOCTYPE html> <html> <head> <style> p { color: blue; font-size: 14px; } /* тег, специфічність 0,0,0,1 */ .highlight { color: red; } /* клас, специфічність 0,0,1,0 */ </style> </head> <body> <!-- color: red від .highlight, font-size: 14px від p (конфлікту немає) --> <p class="highlight">Червоний текст, 14px.</p> </body> </html> ``` `.highlight` виграє `color`. Але `font-size` з `p` все одно застосовується, бо жодне інше правило його не оголошує. Обидва правила вносять свій внесок у підсумковий стиль. Ось що означає злиття на практиці. ### Каскад у React + Tailwind ```jsx /* App.css */ .button { background: gray; padding: 8px; border-radius: 4px; } /* Tailwind генерує: */ /* .bg-blue-500 { background-color: rgb(59 130 246); } */ function Button({ primary }) { return ( <button className={`button ${primary ? 'bg-blue-500' : 'bg-gray-500'}`}> Натисни </button> ); } /* Результат для primary-кнопки: background: rgb(59 130 246) від Tailwind (рівна специфічність, підключається пізніше) padding: 8px від .button (конфлікту немає, зливається) border-radius: 4px від .button (конфлікту немає, зливається) */ ``` Обидва `.button` і `.bg-blue-500` - класові селектори з однаковою специфічністю. Tailwind виграє `background` за порядком у коді: його таблиця стилів підключається після твоєї. Padding і border-radius з `.button` зливаються, бо Tailwind їх не оголошує. Це стандартна поведінка Tailwind у Next.js-проектах.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.