13 Модуль 3 Знакомство с CSS 15 мин урок 13 из 25

Каскад: почему стиль «не работает»

Как браузер выбирает между спорящими правилами: важность, вес селектора, порядок. Плюс наследование и честное место !important.

Что ты научишься делать

  • Посчитаешь вес любого селектора в уме
  • Найдёшь причину, по которой твоё правило проигрывает чужому
  • Переопределишь чужой стиль, не прибегая к !important

#Буква C в слове CSS

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

Спор решается в три шага, строго по порядку. Как только на очередном шаге определился победитель, дальше браузер не идёт.

  1. Важность

    Объявление с !important побеждает любое обычное — независимо от селектора и порядка.

  2. Специфичность

    Побеждает правило с более «тяжёлым» селектором. Как считается вес — прямо ниже.

  3. Порядок

    Если важность и вес одинаковые, побеждает то правило, которое написано позже.

#Специфичность: три числа

Вес селектора — это три числа, которые сравниваются слева направо, как версии программы.

  • Первое — количество id в селекторе.
  • Второе — количество классов, атрибутов и псевдоклассов.
  • Третье — количество тегов и псевдоэлементов.

Сравнение идёт по первому различию. Один id перевесит хоть двадцать классов: 1-0-0 больше, чем 0-20-0.

СелекторВесПочему
*0-0-0Универсальный селектор веса не имеет
p0-0-1Один тег
.card0-1-0Один класс
.card p0-1-1Класс и тег
a:hover0-1-1Псевдокласс считается за класс
input[type="text"]0-1-1Атрибут тоже считается за класс
#hero1-0-0Один идентификатор
#hero .card p1-1-1Всё вместе
p::before0-0-2Псевдоэлемент считается за тег

Весы специфичности

Считает вес селектора по формуле «id — класс — тег».

СелекторВес
p0-0-1
.card p0-1-1
#hero .card1-1-0
a:hover0-1-1

#Смотрим, как решается спор

Река каскада

Показывает по шагам, какое правило победило и почему.

ШагЧто решает
1Важность: !important побеждает всё
2Специфичность: id весомее класса, класс весомее тега
3Порядок: при равном весе выигрывает правило ниже

#Наследование

Часть свойств передаётся детям автоматически. Задал color у body — его получили все абзацы, ссылки (нет, ссылки не получили, у них свой цвет), заголовки и списки внутри.

Наследуются в основном свойства, связанные с текстом: color, font-family, font-size, line-height, text-align, letter-spacing, visibility.

Не наследуются свойства, связанные с коробкой и оформлением: margin, padding, border, background, width, display. Иначе рамка у body появилась бы вокруг каждого абзаца.

Что унаследовалось, а что нет
В песочницу

Наследованием можно управлять вручную. Значение inherit заставляет свойство взять значение родителя, даже если оно обычно не наследуется. initial возвращает значение по умолчанию, unset — наследует, если свойство наследуемое, и сбрасывает, если нет.

CSSЧастый приём
/* Кнопка не наследует шрифт автоматически — вернём принудительно */button {  font: inherit;}/* Ссылка в меню должна быть цвета текста, а не синей */.menu a {  color: inherit;}

#!important — и почему его не любят

!important выигрывает у всего. Именно поэтому он опасен: перебить его можно только другим !important с более тяжёлым селектором. Начинается гонка вооружений, и через месяц половина файла состоит из восклицательных знаков.

Есть ровно два случая, когда он уместен: перекрыть стили сторонней библиотеки, к которой нет доступа, и служебные правила вроде отключения анимаций для людей, которым движение мешает.

Так не надо

.card .title {
  color: red !important;
}

Проблема решена ударом кувалды. Следующий стиль для этого заголовка перебить уже не получится — только ещё одним !important.

Так надо

.card .title {
  color: red;
}

/* или, если надо перебить чужое правило: */
.page .card .title {
  color: red;
}

Достаточно добавить один класс — вес вырос, правило победило, и его по-прежнему можно перекрыть в будущем.

#Практический вывод

Чтобы каскад не превращался в борьбу, держи вес селекторов низким и примерно одинаковым.

  • Стили — на классы. Один класс на правило, если получается.
  • id в CSS не использовать: 1-0-0 против всего остального — это сразу неравный бой.
  • Цепочки — не длиннее двух уровней.
  • Файл читается сверху вниз: сначала общее (сброс, типографика), потом компоненты, потом мелкие правки.

Где спотыкаются почти все

«Я написал правило, а оно не работает»

Почему Почти всегда его перебивает более весомое правило. Иногда — опечатка в селекторе или незакрытая скобка выше по файлу.

Как надо Открой DevTools и посмотри на элемент. Зачёркнутое свойство и есть ответ: рядом написано, какое правило победило.

Стили на id, потому что «так короче»

Почему Вес 1-0-0 нельзя перебить классами. Любая правка потребует ещё одного id или !important.

Как надо В CSS цепляйся за классы. id оставь якорям и label.

Селектор скопирован из DevTools целиком

Почему Браузер выдаёт что-то вроде body > div:nth-child(3) > ul > li:nth-child(2). Такое правило сломается при первой же правке разметки.

Как надо Дай элементу класс и напиши селектор сам.

!important как первое средство

Почему Это не решение, а откладывание проблемы. Через месяц перекрыть такой стиль будет нечем.

Как надо Сначала попробуй добавить класс или переставить правило ниже.

Каскад cascade
Порядок разрешения споров между правилами: важность, специфичность, порядок.
Специфичность specificity
Вес селектора в виде трёх чисел: id — класс — тег.
Наследование inheritance
Передача значения свойства от родителя к потомкам.
inherit / initial / unset global values
Ручное управление наследованием: взять у родителя, вернуть по умолчанию, или то и другое по ситуации.
!important important
Пометка, выигрывающая у обычных объявлений. Крайнее средство.

Проверь себя

  1. Какой вес у селектора <code>.card h2</code>?

    Один класс и один тег: ноль идентификаторов, один класс, один тег.

  2. Два правила: <code>#hero p { color: red }</code> и <code>.card .text p { color: blue }</code>. Какой цвет победит?

    Веса 1-0-1 против 0-2-1. Сравнение идёт по первому числу: один идентификатор перевешивает любые классы.

  3. Какое свойство НЕ наследуется от родителя?

    Наследуется в основном текстовое оформление. Отступы, рамки и фоны — нет, иначе они дублировались бы на каждом вложенном элементе.

  4. Ты написал правило, но оно не применяется. Что сделать первым делом?

    DevTools покажет зачёркнутое свойство и правило-победителя. Дальше решение обычно очевидно.

  5. Что делает <code>:where(.card)</code>?

    <code>:where()</code> обнуляет специфичность. Такое правило легко перекрыть чем угодно — это его смысл.

Задание

Победить чужой стиль без !important

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

Добавь ниже свои правила так, чтобы заголовок стал не меньше 24px и приобрёл другой цвет. Использовать !important и id запрещено.

Открыть в песочнице
    Подсказка 1

    Посчитай вес чужого правила: .card .card__title — это 0-2-0. Твоё должно быть не меньше и стоять ниже.

    Подсказка 2

    Добавь в цепочку класс родителя: .page .card .card__title { … } — получится 0-3-0.

    Показать решение
    HTMLindex.html
    <div class="page">  <article class="card">    <h2 class="card__title">Раф на кокосовом</h2>    <p class="card__text">Мягкий, сладкий, без коровьего молока.</p>  </article></div>
    CSSstyle.css
    /* Чужая библиотека — не трогай этот блок */.card .card__title {  color: #9aa0ad;  font-size: 15px;}/* Твои правила ниже */.page .card .card__title {  color: #6544e0;  font-size: 26px;}

    Проверь себя