Современные селекторы
Псевдоклассы вроде :hover и :first-child проверяют состояние или место элемента. Новые псевдоклассы принимают в скобках другие селекторы и позволяют то, что раньше было невозможно: например, выбрать родителя по тому, что лежит внутри него. Все они работают в современных браузерах.
:is() — один из списка
:is() подходит, если элемент совпадает с любым селектором из списка. Он сокращает повторы:
<style>
:is(h2, h3, h4) { color: steelblue; margin: 4px 0; }
</style>
<h2>Заголовок h2</h2>
<h3>Заголовок h3</h3>
<h4>Заголовок h4</h4>
<p>Абзац не изменился</p>Без :is() пришлось бы писать h2, h3, h4. Выигрыш виден в длинных цепочках: .post :is(h2, h3) a вместо .post h2 a, .post h3 a.
:where() — то же, но без веса
:where() выбирает то же самое, что :is(), но его специфичность — сила селектора в каскаде — всегда равна нулю. Такое правило легко перебить любым другим, поэтому :where() удобен для базовых стилей:
<style>
:where(.article) a { color: seagreen; }
a { color: crimson; }
</style>
<p class="article"><a href="#">Ссылка красная</a>: простой селектор a перебил правило с :where().</p>:not() со списком
:not() выбирает элементы, которые не подходят под селектор. Внутри можно перечислить несколько селекторов через запятую:
<style>
li:not(:first-child, .muted) { color: crimson; }
</style>
<ul>
<li>Первый — не красный</li>
<li>Второй — красный</li>
<li class="muted">Приглушённый — не красный</li>
<li>Четвёртый — красный</li>
</ul>:has() — выбор по содержимому
:has() выбирает элемент, внутри которого есть что-то, подходящее под селектор. Его называют «селектором родителя»: раньше CSS умел смотреть только вниз по дереву, а теперь — и вверх:
<style>
.card { padding: 12px; margin-bottom: 8px; border: 2px solid silver; }
.card:has(svg) { border-color: gold; }
</style>
<div class="card">Карточка без картинки</div>
<div class="card">
<svg width="40" height="40"><circle cx="20" cy="20" r="18" fill="gold"/></svg>
Карточка с картинкой
</div>:has() появился во всех основных браузерах в конце 2023 года.
:has() и состояние формы
:has() реагирует на изменения: родитель может перестроиться, когда внутри отметили флажок. Нажмите на флажок:
<style>
.option { padding: 12px; border: 2px solid silver; }
.option:has(input:checked) { border-color: seagreen; background: honeydew; }
</style>
<label class="option">
<input type="checkbox"> Доставка курьером
</label>Раньше для такого эффекта нужен был JavaScript.
Частая ошибка
Специфичность :is() равна самому сильному селектору в списке. Если в список попал id, правило становится очень тяжёлым и перебивает классы, даже стоя выше:
<style>
:is(#intro, p) { color: crimson; }
.note { color: seagreen; }
</style>
<p class="note">Хотели зелёный, а получили красный</p>Здесь абзац выбран через p, но весь :is() получил вес id. Не смешивайте в одном :is() id и простые селекторы, а для лёгких правил используйте :where().