EvolCode
треки/Веб от нуля до сайта·01 / 11
6 мин чтения

CSS — селекторы и каскад

CSS = «придай элементам внешний вид». Но прежде чем стилизовать, нужно НАЙТИ элементы — это селекторы. И когда два правила противоречат — нужно понимать, что побеждает (каскад). Без этого CSS — сплошное «почему оно не применяется».

Виды селекторов

p — все параграфы (по тегу). .btn — все с классом btn. #header — элемент с id="header" (один на страницу). [type="email"] — атрибут. Комбинации: .btn.primary (оба класса), .card .title (.title ВНУТРИ .card), .card > .title (только прямой ребёнок). Псевдо-классы: :hover (наведение), :focus, :first-child, :not(.disabled). ИИ часто использует [data-mode="active"] — селектор по data-атрибуту.

Специфичность — кто побеждает

Если два правила задают color для одного элемента — побеждает то, у кого выше специфичность. Считается так: id = 100, class/атрибут/псевдокласс = 10, тег = 1. #x (100) > .btn.primary (20) > .btn (10) > p (1). При равной специфичности побеждает то, что НИЖЕ в файле. Поэтому новички часто пишут !important — а потом тонут в конфликтах.

Каскад и наследование

Каскад — последовательность откуда применяются стили: 1) браузерные дефолты 2) внешние CSS 3) <style> в head 4) inline style="...". Inline побеждает всё, кроме !important. Наследование: некоторые свойства передаются от родителя детям (color, font-family) — задаёшь на body и дальше всё подхватывается. Не наследуются: padding, margin, border — это размеры, у каждого элемента свои.

!important — крайняя мера

color: red !important — выигрывает у всего с обычной специфичностью. Кажется удобно, но: 1) когда в проекте 10 !important, новый !important уже не помогает. 2) Чем больше !important, тем сложнее переопределить — особенно сторонним библиотекам или твоей же тёмной теме. Правило: НЕ используй !important. Если приходится — вероятно, специфичность твоего селектора слишком низкая, повысь её.

примерcss
/* === Базовые селекторы === */
p              { color: #333 }              /* все параграфы */
.btn           { padding: 10px 20px }       /* класс */
#header        { background: black }        /* конкретный id */
[type="email"] { border: 2px solid blue }   /* атрибут */

/* === Комбинации === */
.btn.primary       { background: red }      /* оба класса на ОДНОМ элементе */
.card .title       { font-size: 24px }      /* .title ВНУТРИ .card на любой глубине */
.card > .title     { font-size: 24px }      /* только прямой ребёнок */
.row + .row        { margin-top: 16px }     /* следующий брат */
.list .item:not(.done) { opacity: 1 }       /* item который НЕ done */

/* === Псевдо-классы === */
.btn:hover            { background: #f00 }
.input:focus          { border-color: red }
.list-item:first-child { padding-top: 0 }
.list-item:nth-child(odd) { background: #f5f5f5 }

/* === Каскад в действии === */
/* Допустим есть HTML: <p class="warning">Текст</p> */

p              { color: black }   /* специфичность 1 */
.warning       { color: orange }  /* специфичность 10 → ПОБЕЖДАЕТ */

/* Если оба .warning, побеждает тот что ниже: */
.warning       { color: orange }
.warning       { color: red }     /* ← победит он */

/* === Антипаттерн !important === */
.warning       { color: red !important }   /* перебивает всё */
/* Теперь чтобы перекрыть — нужен ещё !important или inline style */
/* Это путь в ад. Лучше не делай. */

/* === Лучше — повысить специфичность === */
.card .warning { color: red }     /* специфичность 20 — победит над .warning */

Селекторы и каскад в реальной CSS

главное
  • 01Селекторы: тег (1), класс/атрибут/псевдо (10), id (100) — складываются
  • 02При равной специфичности побеждает то что НИЖЕ в файле
  • 03`.a .b` — потомок (любая глубина), `.a > .b` — прямой ребёнок
  • 04:hover, :focus, :first-child, :not() — частые псевдо-классы
  • 05Inline style побеждает почти всё (кроме !important)
  • 06!important — антипаттерн. Если хочется — повысь специфичность через комбинацию селекторов
  • 07color и font-family наследуются от родителя, padding/margin/border — нет
проверь себя
01Какой селектор выиграет: `.btn.primary` или `#submit`?
02CSS не применяется. Что проверить ПЕРВЫМ?
03Что значит селектор `.list .item:not(.done)`?
следующий урок: React — что это и зачем