Если вы так боитесь каскада, что отказываетесь его изучать, вы не понимаете веба и лучше вам посмотреть в сторону чего-нибудь попроще в другой области кодинга. Спасибо, что прослушали мой доклад для фронтендеров.
— Эрик Мейер, автор «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
.