Урок 02

Специфичность, каскад, наследование

Что такое каскад

Каскад — механизм, решающий, какое правило применить, если их несколько.

Порядок принятия решения:

  1. Важность — !important vs обычное.
  2. Источник — автор, пользователь, браузер.
  3. Специфичность — насколько «точный» селектор.
  4. Порядок — последнее в файле.

Правило: чем ниже уровень — тем чаще используется.

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

Веса:

  • Inline-стиль — 1000.
  • ID — 100.
  • Класс, атрибут, псевдокласс — 10.
  • Тег, псевдоэлемент — 1.
  • Универсальный * — 0.

Пример:

p                         /* 0-0-1 */
.text                     /* 0-1-0 */
#main                     /* 1-0-0 */
.card .title              /* 0-2-0 */
nav ul li a               /* 0-0-4 */
#main .card a:hover       /* 1-2-1 */

Правило: сравнивать слева направо — 1-0-0 > 0-99-99.

Как считать

Формула: (a, b, c)

  • a — количество ID.
  • b — классов, атрибутов, псевдоклассов.
  • c — тегов и псевдоэлементов.

Практика:

/* 0,0,1 */
p { }

/* 0,1,0 */
.button { }

/* 0,1,1 */
p.button { }

/* 0,1,2 */
p.button::before { }

/* 1,0,0 */
#header { }

/* 1,1,0 */
#header .logo { }

/* 1,2,3 */
#main .card .title span a:hover::before { }

Inline-стили

<p style="color: red">Текст</p>

Специфичность: 1,0,0,0 — выше всего, кроме !important.

Правило: inline — не для постоянного оформления. Только динамика от JS.

!important

p { color: red !important; }

Что делает: перебивает всё, кроме ещё более важного.

Когда использовать:

  • Utility-классы (Tailwind, Bootstrap утилиты).
  • Override сторонних виджетов (без доступа к их CSS).
  • Печать (@media print).

Правило: не использовать для обычных стилей. Признак плохой архитектуры.

Каскад источников

Порядок важности:

  1. Браузерные стили — user agent.
  2. Пользовательские — настройки пользователя в браузере.
  3. Авторские — ваши стили.
  4. Авторские !important.
  5. Пользовательские !important.
  6. Браузерные !important.

Что важно: !important в пользовательских стилях перебивает ваши. Это для доступности.

Порядок в файле

При равной специфичности побеждает последнее:

p { color: blue; }
p { color: red; }   /* победит */

С подключением файлов:

<link href="a.css">
<link href="b.css">   <!-- перебивает a.css при равной специфичности -->

Правило: порядок = приоритет.

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

Наследование — свойства, которые передаются от родителя к потомку.

Наследуемые:

  • color
  • font-family
  • font-size
  • font-weight
  • line-height
  • text-align
  • visibility
  • cursor
  • list-style

НЕ наследуемые:

  • margin
  • padding
  • border
  • background
  • width / height
  • display
  • position

Правило: задали color родителю — все потомки наследуют.

inherit, initial, unset, revert

.child {
    color: inherit;      /* взять у родителя */
    color: initial;      /* дефолтное значение */
    color: unset;        /* наследуемое — inherit, нет — initial */
    color: revert;       /* сбросить до браузерного */
}

Когда использовать:

  • inherit — вернуть наследуемое поведение (например, кнопке от родителя).
  • initial — вернуть дефолт свойства.
  • unset — универсальный сброс.
  • revert — сбросить до браузерного стиля.

Практика: all: unset; — сбросить все свойства элемента.

Наследование форм

Проблема: input не наследует font-family от body:

body { font-family: sans-serif; }
input { /* шрифт — системный, не sans-serif */ }

Решение:

input, button, textarea, select {
    font: inherit;
    color: inherit;
}

Правило: всегда сбрасывать формы до наследования.

Дефолтные стили браузера

Каждый браузер применяет свои стили (user-agent stylesheet).

Примеры:

  • h1 — крупный и жирный.
  • p — отступы сверху и снизу.
  • ul — маркеры и отступ слева.
  • a — синий и подчёркнутый.
  • button — серый с рамкой.

Проблема: разные браузеры — разные дефолты.

Решение: CSS Reset или Normalize.

CSS Reset

*, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

html, body {
    height: 100%;
}

img, picture, svg, video {
    display: block;
    max-width: 100%;
}

input, button, textarea, select {
    font: inherit;
}

p, h1, h2, h3, h4, h5, h6 {
    overflow-wrap: break-word;
}

Что даёт: единое поведение во всех браузерах.

Normalize.css

Альтернатива Reset. Не обнуляет всё, а приводит к единому виду.

Подключение:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/normalize.css">

Что делает:

  • Исправляет баги старых браузеров.
  • Унифицирует дефолты.
  • Не ломает полезные стили (например, курсив em).

Правило: для нового проекта — современный Reset. Для legacy — Normalize.

Пример: каскад в действии

/* Специфичность 0,0,1 */
p { color: black; }

/* Специфичность 0,1,0 — побеждает */
.text { color: blue; }

/* Специфичность 0,1,1 — побеждает */
p.text { color: green; }

/* Специфичность 0,2,0 — побеждает */
.text.highlight { color: red; }

/* Специфичность 1,0,0 — побеждает */
#main { color: purple; }

HTML:

<p id="main" class="text highlight">Цвет: purple</p>

Как избежать проблем

Правила:

  • Не использовать ID для стилей.
  • Максимум 3 уровня вложенности селекторов.
  • BEM-нейминг — .block__element--modifier.
  • Не использовать !important без причины.
  • Utility-классы для коротких правок.

BEM-пример:

.card { }
.card__title { }
.card__title--large { }
.card--featured { }

Что даёт: плоская структура, предсказуемая специфичность.

Инструменты

DevTools:

  • Elements → Styles — все правила на элементе.
  • Зачёркнутое — перезаписано.
  • Computed — итоговые значения.
  • Показать специфичность — в новых браузерах.

Специфичность-калькуляторы:

  • specificity.keegan.st
  • polistat.github.io/specificity

Практика

1. Проверьте каскад:

p { color: blue; }
.text { color: red; }
#first { color: green; }
<p id="first" class="text">Какой цвет?</p>

Ответ: green (ID побеждает).

2. Добавьте inline:

<p id="first" class="text" style="color: orange">Какой цвет?</p>

Ответ: orange (inline побеждает).

3. Сбросьте стили и посмотрите дефолты.

4. Проверьте наследование color, font-family.

Частые ошибки

1. !important для всего:

color: red !important;

Решение: починить специфичность.

2. ID для стилей:

#header { ... }

Решение: классы.

3. Глубокая вложенность:

.a .b .c .d .e .f { }

Решение: BEM или короткие.

4. Стили форм не сброшены:

input не наследует font-family

Решение: input, button { font: inherit; }.

5. Не понимать порядок:

/* Ожидание: работает первое */

Решение: последнее побеждает.

6. Reset ломает доступность:

/* Убрали focus у ссылок */
a:focus { outline: none; }

Решение: :focus-visible.

7. Забыть про дефолты:

h1 жирный по умолчанию

Решение: Reset.

8. Наследование в <p> с <div>:

<p><div>...</div></p>   <!-- невалидно -->

Решение: правильная вложенность.

Итог

  • Каскад — порядок применения.
  • Специфичность — (id, class, tag).
  • Inline > ID > класс > тег.
  • !important — исключение, не правило.
  • Наследование — только часть свойств.
  • Формы не наследуют — сбросить.
  • Reset / Normalize — для единообразия.
  • BEM — плоские селекторы.
  • DevTools — показать каскад.

Дальше — цвета, единицы, шрифты, текст.