Подробности CSS-селектора :is(), о которых вы, возможно, не знали
Использовать :is() или не использовать :is()?
Рассмотрим следующие сложные селекторы:
.a .b .c {
background: green;
}
.a :is(.b .c) {
background: green;
}
Они могут выглядеть одинаково, но ведут себя по-разному… второй селектор выбирает больше элементов, чем вы могли бы ожидать.
Попробуйте сами
В демо ниже есть две вложенные структуры разметки:
<div class="a">
<div class="b">
<div class="c"></div>
</div>
</div>
<div class="b">
<div class="a">
<div class="c"></div>
</div>
</div>
Используйте выпадающий список, чтобы увидеть, какие элементы соответствуют селекторам .a .b .c и .a :is(.b .c).
При выборе .a .b .c будет выбрана первая .c. Но при выборе .a :is(.b .c) вы заметите, что обе .c выбираются… и для многих это очень неожиданно.
.a .b .c
Этот селектор состоит из 3 частей: .a, .b и .c. При попытке найти подходящие элементы браузер сначала выберет все элементы .c и затем проверит, есть ли у них родитель с классом .b. Если это так, он затем проверит, является ли этот .b дочерним элементом .a.
.a :is(.b .c)
Этот селектор состоит из 2 частей: .a и :is(.b .c). Первая часть, которая проверяется, это :is(.b .c), и она совпадает с элементами .c, у которых есть предок с классом .b. Если это так, браузер продолжит проверку и удостоверится, что у найденного элемента .c также есть предок с классом .a.
Таким образом, .a :is(.b .c) выберет все элементы .c в примере выше, так как селектор переводится как «найди элементы .c, у которых есть предки с классами .b и .a». Это означает, что будет выбран и этот элемент .c:
<div class="a b">
<div class="c"></div>
</div>
Если вы не можете это понять, знайте, что .a :is(.b .c) по сути разворачивается в такой набор селекторов:
.a .b .c
.b .a .c
.a.b .c
Почему это важно?
Хотя я сам не стал бы так писать селектор, это становится весьма актуальным из-за CSS Nesting, который сейчас специфицируется. В этом случае селектор вложенности (&) разворачивается в :is().
Рассмотрим этот вложенный блок:
.b .c {
.a & {
background: green;
}
}
Когда & разворачивается в внешний селектор, обёрнутый в :is(), этот фрагмент превращается в:
.a :is(.b .c) {
background: green;
}
Это может показаться нелогичным для тех, кто раньше использовал Sass и другие препроцессоры. В Sass & просто заменяется внешним селектором:
.a .b .c {
background: green;
}
Как показано ранее, они ведут себя по-разному.
Есть ли ещё что-то о :is()?
Как упоминалось в предыдущей статье, вот ещё несколько важных моментов о :is():
- Список селекторов внутри :is() прощает ошибки.
- Специфичность :is() соответствует наиболее специфичному аргументу.
- :is() не работает с селекторами псевдоэлементов (пока).