Каскад и специфичность: что побеждает в CSS

Когда несколько правил CSS претендуют на один и тот же элемент, побеждает не то, что написано раньше или позже само по себе, а то, что выигрывает по специфичности - весу селектора. Специфичность считается по трём разрядам: id, классы/атрибуты/псевдоклассы, теги/псевдоэлементы - и сравниваются они не суммой, а по старшинству разряда, как в системе счисления.

Попробуй прямо в этом окне: текст становится зелёным, хотя по обычной специфичности должен был победить #main с его id и стать оранжевым (tomato) - именно !important на классе .txt перебивает id без !important. Удали строку с !important - и текст сразу станет оранжевым: сработает id, у которого специфичность выше, чем у класса и тега.

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

У каждого селектора есть вес из трёх чисел: сколько в нём id, сколько классов/атрибутов/псевдоклассов и сколько тегов/псевдоэлементов. Эти три числа сравниваются по очереди слева направо, а не складываются в одно общее число - поэтому один id всегда побеждает, сколько бы классов ни было в конкурирующем селекторе.

#main { } (1 id, 0 классов, 0 тегов) побеждает .a.b.c.d.e { } (0 id, 5 классов, 0 тегов) - даже пять классов не перевешивают один id.

.card .title.big.red { }, ожидая, что три класса "победят сильнее" - три класса всё равно остаются во втором разряде, а не превращаются в id. Побеждать будут именно по числу классов в этом разряде, а не по общему "напору" селектора.

Каскад - что решает, если вес одинаковый

Если у двух правил специфичность получилась абсолютно одинаковой, вступает в игру каскад: побеждает то правило, которое в коде написано НИЖЕ. Но это самый последний аргумент - он работает только при полном равенстве специфичности, а не всегда.

.txt { color: blue; } ... .txt { color: green; } - специфичность у обоих правил одинаковая, побеждает то, что ниже, - зелёный.

#main { color: tomato; } написанное ВЫШЕ по коду, чем .txt { color: green; }, ожидая, что порядок в коде важнее специфичности - на самом деле id выигрывает в любом случае, независимо от того, что написано ниже: порядок в коде решает только при равной специфичности.

!important - козырь, который ломает обычный порядок

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

p { color: black !important; } победит даже <p style="color: tomato;"> - !important на теге перебивает инлайн-стиль без !important, хотя обычно инлайн-стиль сильнее любого селектора.

.fix { color: red !important; } как быстрый способ "просто заставить работать" - в реальном проекте единственный способ потом переопределить такое правило - это другой !important с не меньшей специфичностью, и с каждым таким патчем становится сложнее понять, что вообще управляет стилями страницы.

Из истории Слово «каскадные» в самом названии CSS (Cascading Style Sheets) появилось не случайно - именно механизм каскада был в спецификации с первого дня: CSS1 1996 года уже описывал порядок разрешения конфликтов между правилами. А вот !important как отдельная возможность появилась там же, в CSS1, для того чтобы автор страницы или сам пользователь браузера мог настоять на своём стиле поверх остальных правил - в разделе спецификации, посвящённом каскаду. Источник: w3.org - спецификация CSS1, 1996.

Частые ошибки новичков

ОшибкаЧто происходитКак исправить
Думать, что специфичность складывается в одно число На самом деле три разряда (id / класс / тег) сравниваются по очереди, а не суммируются - десять классов не обгонят один id Сравнивать разряды по старшинству: сначала id, потом классы, потом теги
Хвататься за !important, чтобы "просто заставить работать" Переопределить такое правило потом можно только другим !important не меньшей специфичности - с каждым таким патчем разобраться в стилях становится сложнее Сначала понять, почему нужное правило не побеждает, и поправить сам селектор, а не глушить проблему через !important
Считать, что порядок правил в коде решает всегда Порядок в коде - это самый последний аргумент, он работает только при полностью одинаковой специфичности у конкурирующих правил Сначала сравнивать специфичность, и только при равенстве смотреть, какое правило ниже
Забывать, что комбинаторы и универсальный селектор * не добавляют веса article > p и article p дают одинаковую специфичность (0 id, 0 классов, 2 тега) - сам знак > ничего не весит Считать специфичность только по реальным id/классам/тегам внутри селектора, комбинаторы и * пропускать

Шпаргалка

ЧтоВес
idСтарший разряд - побеждает любое число классов и тегов
Класс, атрибут, псевдоклассСредний разряд
Тег, псевдоэлементМладший разряд
Инлайн-стиль (style=" ")Выше всех трёх разрядов, но проигрывает !important
!importantПереворачивает обычный порядок - побеждает почти всё, кроме более "важного" правила с не меньшей специфичностью

Коротко: отвечаем на вопросы

Можно ли переопределить правило с !important?

Да, но только другим правилом с !important, у которого специфичность не меньше, а при равной специфичности - которое написано ниже по коду. Обычное правило без !important, даже с более высокой специфичностью, его не перебьёт.

Когда использование !important вообще оправдано?

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

Складывается ли специфичность нескольких классов в одно число вместе с тегами?

Нет, три разряда (id, классы, теги) сравниваются отдельно по старшинству, а не суммируются в одно число - поэтому десять тегов в селекторе всё равно проиграют одному-единственному классу.

Категория
css
Поделиться в социальных сетях

Отправить комментарий

0 Комментарии

Отправить комментарий (0)

#buttons=(Хорошо) #days=(20)

Мы используем файлы cookie для улучшения работы сайта. Подробнее
Хорошо
×