Принцип каскада

Время чтения: 6 мин

Если вы так боитесь каскада, что отказываетесь его изучать, вы не понимаете веба и лучше вам посмотреть в сторону чего-нибудь попроще в другой области кодинга. Спасибо, что прослушали мой доклад для фронтендеров.

— Ерик Мейер, автор «CSS: The Definitive Guide», источник

Большой Каскад в Петергофе

Каскад — одно из важнейших понятий в CSS. Само название CSSCascading Style Sheets, «каскадные таблицы стилей» явно упоминают это неочевидное определение.

Точнее, в определении каскада принимает участие не только специфичность, но и в первую очередь источник этих правил и область видимости. Также имеет важное значение порядок в коде (какие свойства были объявлены «позже», те «важнее»).

Источники правил

Секция статьи "Источники правил"

Чем выше — тем «важнее»:

  1. Стили во время CSS-переходов (transition);
  2. Браузерные стили с !important;
  3. Пользовательские стили с !important;
  4. Авторские (мы с вами пишем именно эти стили) стили с !important;
  5. Стили во время анимаций;
  6. Обычные (т. е. без !important) авторские стили;
  7. Обычные пользовательские стили;
  8. Обычные браузерные стили.

Иногда браузеры нарушают этот порядок — порой осознанно (например, могут запретить сделать слишком мелкий шрифт в полях ввода, как это делал Google Chrome) или по ошибке (до недавнего времени стили при анимации перекрывали остальные стили только в Firefox).

Область видимости

Секция статьи "Область видимости"

Понимание области видимости лучше всего начать с указания стилей в атрибуте тега style — их область видимости ограничена только тем тегом, в котором они указаны. Т. е. если вы описали style тегу <li>, то эти стили применятся только к этому тегу, остальные <li> не «увидят» эти свойства:

Открыть демо в новой вкладке

Со свойствами, описанными через классические 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, атрибуты и псевдоклассы) и их совокупность и комбинации. Самый простой способ разобраться в этом разнообразии — использовать так называемый калькулятор специфичности. Можно воспользоваться одним из множества онлайн-сервисов:

Подробнее про специфичность можно прочитать в статье «Специфичность».

Порядок в коде

Секция статьи "Порядок в коде"

Тут ещё проще — при равной специфичности правила, написанные ниже по ходу «чтения» переопределяют написанное выше:

        
          
          <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

Секция статьи "Начальное значение — initial"

Любое CSS-правило можно «сбросить» на начальное значение (то, которое было у правила «до» того как было установлено явно разработчиком): color станет #000, positionstatic, displayinline, padding, margin0 и так далее.

Заимствование у «родителя» — inherit

Секция статьи "Заимствование у «родителя» — inherit"

Некоторые свойства автоматически наследуются от «родителя» автоматически (color, font, text-align и другие). Но можно и явно позаимствовать какое-то значение у родителя:

Открыть демо в новой вкладке

Отмена значения — unset

Секция статьи "Отмена значения — unset"

По своему поведению unset чем-то похож на initial + inherit — если это свойство ненаследуемое от родителя — оно «сбросится» до начального значения, наследуемое — получит значение «родителя».

Сброс значения — revert

Секция статьи "Сброс значения — revert"

Это менее «строгий» режим сброса — он отменяет все установленные разработчиком значения для данного свойства до значения, которое считается браузером «значением по умолчанию».

Подсказки

Секция статьи "Подсказки"

💡 В CSS есть такое «волшебное» свойство — all — это своеобразный шорткат (сокращённый формат записи), который «внутри» себя содержит все-все CSS-свойства. В сочетании с initial, inherit, unset или revert это позволяет повлиять на каскад в одну строчку.

Все наследуемые свойства .widget и вложенных элементов будут сброшены:

        
          
          .widget {  all: revert;}
          .widget {
  all: revert;
}

        
        
          
        
      

На практике

Секция статьи "На практике"

Realetive

Секция статьи "Realetive"

🛠 Понимание каскада — один из ключевых моментов в понимании работы CSS. С опытом вы научитесь так эффективно писать селекторы и группировать стили, что сам уровень каскада будет минимальным — это ускоряет «чтение» кода и упрощает поддержку. Ну и в идеале — исключить необходимость использования !important.