Специфичность CSS для :not(), :has() и :matches()

Специфичность CSS для :not(), :has() и :matches()

От автора: несколько лет назад я написал короткую статью про специфичность CSS, близость элементов и обратные псевдоклассы. Все в ней по-прежнему актуально, но у меня есть некоторые обновления.

Во-первых, я хотел бы прояснить то, что некоторые люди, возможно, нашли сбивающим с толку. В этом посте я сказал: Но оказывается, что обратный псевдо-класс не считается псевдо-классом.

Это может быть понято некоторыми людьми так, что вся отрицательная часть селектора игнорируется для целей специфичности, особенно если вы не знаете спецификации. Поэтому рассмотрим следующее:

div:not(.one) p

В порядке слева направо это селектор элемента (div), обратный псевдо-класс (:not), селектор класса (.one) и селектор другого элемента (p). Два элемента селектора и один селектор классов подсчитываются по специфичности, что дает общее число 0,0,1,2. Это та же специфичность, что и для div.one p, хотя два селектора выбирают разные вещи.

В старые добрые дни это было достаточно легко, потому что :not() мог содержать только простой селектор. Все стало сложнее теперь, когда :not() может принимать сгруппированные селекторы. Поэтому в какой-то момент мы сможем сказать:

div:not(.one, .two, #navbar) p

Таким образом, будет выбран любой элемент p, который не происходит от div, который имеет класс, содержащий one или two (или оба), или имеющий идентификатор navbar.

Но как мы вычисляем специфику всего селектора? Просто сложить все части? Нет. Рабочая группа недавно решила, что специфика, внесенная внутри :not(), будет равна единому селектору с наивысшей специфичностью. Так что в div:not(.one, .two, #navbar) p селектор #navbar дает 0,1,0,0 в общую специфичность селектора, что даст всего 0,1,0,2. Специфичность one и two игнорируется.

Этот же подход будет использоваться для псевдо-классов :has() и :matches(). Таким образом, мы получаем следующее:

:matches(nav, header, footer#pageend) a[href] {color: silver;} /* 0,1,1,2 */ article:has(a.external, a img) /* 0,0,1,2 */ input:not([type="radio"], [type="checkbox"]) /* 0,0,1,1 */ 

В первом случае части, которые складываются вместе, дают footer#pageend и a[href], поэтому это один идентификатор, один атрибут и два элемента. Во втором — это article и a.external для одного класса и двух элементов. И в последнем мы добавляем input и любой из селекторов атрибутов [type = «»], так как их специфичности равны, что означает, что мы добавляем один атрибут и один элемент.

Насколько мне известно, до сих пор не существует концепции близости дерева DOM в CSS. Я по-прежнему готов держать пари, что это будет оставаться так, хотя поставил бы на это меньше денег, чем шесть лет назад.

Автор: Eric A. Meyer

Источник: https://meyerweb.com/

Редакция: Команда webformyself.