Если вы так боитесь каскада, что отказываетесь его изучать, вы не понимаете веба и лучше вам посмотреть в сторону чего-нибудь попроще в другой области кодинга. Спасибо, что прослушали мой доклад для фронтендеров.
— Эрик Мейер, автор «CSS: The Definitive Guide», источник

Каскад — одно из важнейших понятий в CSS. Само название CSS — Cascading Style Sheets, «каскадные таблицы стилей» явно упоминают это неочевидное определение.
Точнее, в определении каскада принимает участие не только специфичность, но и в первую очередь источник этих правил и область видимости. Также имеет важное значение порядок в коде (какие свойства были объявлены «позже», те «важнее»).
Источники правил
СкопированоЧем выше — тем «важнее»:
- Стили во время CSS-переходов (
transition); - Браузерные стили с
!important; - Пользовательские стили с
!important; - Авторские (мы с вами пишем именно эти стили) стили с
!important; - Стили во время анимаций (
animation); - Обычные (т. е. без
!important) авторские стили; - Обычные пользовательские стили;
- Обычные браузерные стили.
Иногда браузеры нарушают этот порядок — порой осознанно (например, могут запретить делать слишком мелкий шрифт в полях ввода, как это делал Google Chrome) или по ошибке (до недавнего времени стили при анимации перекрывали остальные стили только в Firefox).
Область видимости
СкопированоПонимание области видимости лучше всего начать с указания стилей в атрибуте тега style — их область видимости ограничена только тем тегом, в котором они указаны. Т. е. если вы описали style тегу <li>, то эти стили применятся только к этому тегу, остальные <li> не «увидят» эти свойства:
<ul> <li>Этот пункт имеет CSS-свойства по умолчанию</li> <li>И этот тоже</li> <li style="color: #2E9AFF">Текст в этом (и только в этом) теге будет синим</li> <li>Снова обычное оформление</li></ul>
<ul>
<li>Этот пункт имеет CSS-свойства по умолчанию</li>
<li>И этот тоже</li>
<li style="color: #2E9AFF">Текст в этом (и только в этом) теге будет синим</li>
<li>Снова обычное оформление</li>
</ul>
Со свойствами, описанными через классические CSS-селекторы (классы, теги, id, атрибуты) иначе — чем точнее мы описываем правило для селектора, тем сильнее мы суживаем область видимости (т. е. как бы точнее прицеливаемся), тем самым увеличивая и приоритетность правила. Но это работает до тех пор, пока CSS-правило не содержит «подлого» !important. Именно поэтому их использование считается плохой практикой — они «меняют правила игры». Это правило мгновенно становится приоритетнее, но чем шире область видимости — тем оно важнее 🤯
Специфичность
СкопированоСамое простое и очевидное понятие в определении каскада. Когда мы описываем стили (инлайном в теге или на селектор в <style> или файле), каждое правило имеет свой вес. Правила, описанные инлайном перебивают правила на селектор, но не отменяют правила с !important (отменяют, если инлайн-правило тоже описано с !important).
Установим цвет текста абзаца в красный:
<style>p { color: red;}</style><p> Цвет текста будет красным — единственное правило описано в теге <style>.</p>
<style>
p {
color: red;
}
</style>
<p>
Цвет текста будет красным — единственное правило описано
в теге <style>.
</p>
Теперь переопределим цвет текста более специфичным инлайн-правилом:
<style>p { color: red;}</style><p style="color: blue"> Цвет текста стал синим — инлайн «перебивает» <style>.</p>
<style>
p {
color: red;
}
</style>
<p style="color: blue">
Цвет текста стал синим — инлайн «перебивает» <style>.
</p>
Повысим специфичность, добавив !important в правила селектора:
<style>p { color: red !important;}</style><p style="color: blue"> Цвет текста снова стал красным за счёт !important в <style>.</p>
<style>
p {
color: red !important;
}
</style>
<p style="color: blue">
Цвет текста снова стал красным за счёт !important в <style>.
</p>
Последний «шанс» разработчику повлиять на правило — добавить !important в инлайн-стиль:
<style>p { color: red !important;}</style><p style="color: blue !important"> Цвет текста снова синий — !important инлайн-правила «перебивает» даже !important в <style>.</p>
<style>
p {
color: red !important;
}
</style>
<p style="color: blue !important">
Цвет текста снова синий — !important инлайн-правила «перебивает» даже
!important в <style>.
</p>
Инлайн-стили и !important — крайние меры влияния на стилизацию, правильнее описывать стили в селекторах в файлах. Но разные правила можно описать так, что они будут претендовать на одну и ту же сущность (тег и его содержимое). В этом случае на применимость правила будет влиять специфичность, т. е. тип (тег, класс, id, атрибуты и псевдоклассы) и их совокупность и комбинации. Самый простой способ разобраться в этом разнообразии — использовать так называемый калькулятор специфичности. Можно воспользоваться одним из множества онлайн-сервисов:
- Specificity Calculator
- CSS Specificity calculator | Polypane Browser for Developers
- CSS Specificity Calculator. * CodeCaptain
Подробнее про специфичность можно прочитать в статье «Специфичность».
Порядок в коде
СкопированоТут ещё проще — при равной специфичности правила, написанные ниже по ходу чтения переопределяют написанное выше:
<style>.color_red { /* Определяем начальное значение */ color: red;}.color_red { /* Переопределяем написанное ранее правило */ color: blue;}</style><p class="color_red">Цвет текста — синий!</p>
<style>
.color_red {
/* Определяем начальное значение */
color: red;
}
.color_red {
/* Переопределяем написанное ранее правило */
color: blue;
}
</style>
<p class="color_red">Цвет текста — синий!</p>
Влияние на каскад 👻
СкопированоПомимо знания как и где написать селектор, можно управлять каскадом с помощью CSS-свойств!
Начальное значение — initial
СкопированоЛюбое CSS-правило можно сбросить на начальное значение — то, которое было у правила до того как было установлено явно разработчиком. color станет #000, position — static, display — inline, padding и margin — 0 и так далее.
Заимствование у родителя — inherit
СкопированоНекоторые свойства наследуются от родителя автоматически (color, font, text и другие). Но можно и явно позаимствовать какое-то значение у родителя:
<div class="wrapper"> <div class="inner"></div></div>
<div class="wrapper">
<div class="inner"></div>
</div>
.wrapper { background-color: #2E9AFF; border: 10px solid #FFFFFF;}.inner { background-color: #F498AD; border: inherit;}
.wrapper {
background-color: #2E9AFF;
border: 10px solid #FFFFFF;
}
.inner {
background-color: #F498AD;
border: inherit;
}
Отмена значения — unset
СкопированоПо своему поведению unset чем-то похож на initial + inherit — если это свойство ненаследуемое от родителя — оно сбросится до начального значения, наследуемое — получит значение родителя.
Сброс значения — revert
СкопированоЭто менее строгий режим сброса — он отменяет все установленные разработчиком значения для данного свойства до значения, которое считается браузером «значением по умолчанию».
Подсказки
Скопировано💡 В CSS есть такое волшебное свойство — all — это своеобразный шорткат (сокращённый формат записи), который внутри себя содержит все-все CSS-свойства. В сочетании с initial, inherit, unset или revert это позволяет повлиять на каскад в одну строчку.
Все наследуемые свойства .widget и вложенных элементов будут сброшены:
.widget { all: revert;}
.widget {
all: revert;
}
На практике
Скопированосоветует
Скопировано🛠 Если вы знакомы с JavaScript, то каскад можно представить как создание объекта через спред-синтаксис на основе приоритета стилей:
const styles = { ...inheritedStyles, ...tagStyles, ...classStyles, ...idStyles, ...inlineStyles, ...importantStyles, ...transitionStyles}
const styles = {
...inheritedStyles,
...tagStyles,
...classStyles,
...idStyles,
...inlineStyles,
...importantStyles,
...transitionStyles
}
советует
Скопировано🛠 Понимание каскада — один из ключевых моментов в понимании работы CSS. С опытом вы научитесь так эффективно писать селекторы и группировать стили, что сам уровень каскада будет минимальным — это ускоряет «чтение» кода и упрощает поддержку. Ну и в идеале — исключить необходимость использования !important.