Каскадность в CSS: как вычисляется специфичность (приоритет) стилей
CSS — это каскадные таблицы стилей (Cascading Style Sheets). Каскадность — это главный принцип CSS — приоритет одних правил/стилей над другими, когда одни стили перебивают другие. Это понятие также называется "специфичностью селектора".
Читайте также о специфичности: https://developer.mozilla.org/ru/docs/Web/CSS/Specificity
Смотрите также:
При вычислении приоритета браузер определяет «вес» каждого CSS-правила. Вес правила — это сумма весов каждого элемента селектора.
Таблица весов каждого элемента селектора:
| Тип селектора | Описание селектора | Вес (число) |
|---|---|---|
| * | универсальный селектор | 0 |
| div | тег | 1 |
| ::first-letter, ::before, ::after | псевдоэлемент | 1 |
| .class | класс | 10 |
| :hover, :not() | псевдокласс | 10 |
| [атрибут="значение"] | селектор атрибута | 10 |
| #content | селектор по id | 100 |
| style="color:red;" | стили в атрибуте style | 1000 |
| !important | суффикс увеличения веса | 10000 |
Пример подсчета веса:
#content .text p { color: red; } /* 100 + 10 + 1 = 111 */
.text p { color: blue; } /* 10 + 1 = 11 */
Сильные (по весу) стили заменяют слабые, и элемент получает стили от самых «весомых» правил. Это и есть каскадность.
Тег <p> внутри элемента .text получит стиль color: red;, а не color: blue;, потому что число 111 больше, чем 11.
Если вес одинаковый, то применяются те стили, которые указаны позднее — ближе к концу HTML-страницы (ниже в коде).
На практике считать приоритеты не нужно, но важно понимать, как это работает и какой из элементов селектора весомее остальных.
Еще примеры подсчета веса:
* {} /* 0 */
li {} /* 1 */
li::first-line {} /* 2 */
ul li {} /* 2 */
ul ol + li {} /* 3 */
ul li.red {} /* 12 */
li.red.level {} /* 21 */
li:not(.red) {} /* 11 */
li:not(.red):not(.green) {} /* 11 */
.foo {} /* 10 */
.foo[class] {} /* 20 */
#t34 {} /* 100 */
#content #wrap {} /* 200 */
Трюк с увеличением веса. Допустим, нужно увеличить приоритет стилей, не добавляя неуниверсальных селекторов. Это можно сделать:
- продублировав селектор,
- добавив селектор атрибута или псевдокласса.
.class.class { color: blue; } /* вес = 20 */
.class[class] { color: blue; } /* вес = 20 */
.class { color: red; } /* вес = 10 */
img[src] {} /* вес = 11 */В объяснении выше расчет был показан в виде чисел (десяток, соток и тысяч), потому что по моему так проще понять и проще считать (если нужно).
В реальности специфичность рассчитывается не как показано выше, а на основе четырёх уровней, которые часто обозначаются как A, B, C, D:
- A (встроенные стили): Самая высокая специфичность.
- B (ID): Высокая специфичность.
- C (классы, атрибуты, псевдоклассы): Средняя специфичность.
- D (элементы, псевдоэлементы): Низкая специфичность.
Структура оценки специфичности: (A, B, C, D)
- A = Встроенные стили → 1, 0, 0, 0
- B = Количество селекторов ID → 0, 1, 0, 0
- C = Количество селекторов class, атрибутов или псевдоклассов → 0, 0, 1, 0
- D = Количество селекторов элементов или псевдоэлементов → 0, 0, 0, 1
Например:
#content .button:hover a { color: orange; } // 0, 1, 2, 1Приоритет @media
Медиаправила @media (max-width: 500px) {} не участвуют в подсчете приоритета (веса).
Поэтому они всегда должны располагаться ниже всех остальных правил, чтобы перебивать предыдущие правила с таким же весом (приоритетом).
Правильно:
.section { width: 100%; }
@media (max-width: 500px) {
.section { width: 50%; }
}
Неправильно:
@media (max-width: 500px) {
.section { width: 50%; }
}
.section { width: 100%; }