Kodokon kodokon.com

Современные селекторы: :has, :is, :where, продвинутый :nth-child

Используй недавние функциональные псевдоклассы, чтобы выбирать по содержимому, группировать селекторы без раздувания специфичности и попадать в сложные шаблоны.

9 мин · 3 вопросов

Открыть этот урок в Kodokon

:is() и :where() оба группируют селекторы, но расходятся в одном решающем моменте: специфичность. :is(nav, .menu, #main a) берёт специфичность самого сильного из своих аргументов (здесь - идентификатора), даже если совпадает именно nav. У :where() специфичность нулевая, какими бы ни были аргументы. Практическое следствие: :where() - идеальный инструмент для сбросов и стилей по умолчанию в дизайн-системе, которые затем перебивает без борьбы любой простой селектор по классу.

CSS
:where(h1, h2, h3, h4) {
  margin-block: 0;
  line-height: 1.2;
}

:is(article, aside, section) :is(h2, h3) {
  font-family: var(--font-heading);
}

.prose :is(ul, ol) li + li {
  margin-top: 0.5em;
}
Группировка и контроль специфичности

:has() наконец разворачивает направление чтения: селектор нацелен на элемент-хозяин, а не на то, что внутри него. .card:has(> img) выбирает карточку, у которой прямой потомок - изображение. В связке с псевдоклассами состояния это позволяет передавать информацию вверх без JavaScript: стилизовать подпись, когда её поле невалидно, форму - когда поле в фокусе, строку таблицы - когда её флажок отмечен.

CSS
.field:has(input:invalid:not(:focus)) label {
  color: #dc2626;
}

.card:has(> img) {
  padding-top: 0;
}

tr:has(input[type="checkbox"]:checked) {
  background: #eef2ff;
}
Выбор по содержимому или внутреннему состоянию

По :nth-child() нужно закрепить два навыка. Во-первых, чтение формул An+B: 2n (чётные), 2n+1 (нечётные), -n+3 (первые три), n+4 (с четвёртого и до конца); диапазон «со 2-го по 5-й» записывается комбинацией :nth-child(n+2):nth-child(-n+5). Во-вторых, более свежий синтаксис of S: :nth-child(2n of .visible) считает только среди подходящих потомков .visible, тогда как .visible:nth-child(2n) считает всех потомков, а уже потом фильтрует - два совершенно разных результата, как только между ними вклиниваются другие элементы.

CSS
tr:nth-child(odd) {
  background: #fafafa;
}

li:nth-child(-n + 3) {
  font-weight: 600;
}

li:nth-child(n + 2):nth-child(-n + 5) {
  border-top: 1px solid #e5e7eb;
}

.row:nth-child(2n of .visible) {
  background: #eef2ff;
}
Формулы An+B и синтаксис of S

Проверка знаний

Убедись, что запомнил ключевые моменты этого урока.

  1. Какова специфичность :where(#main, .nav, a)?
    • Как у идентификатора, то есть (1,0,0)
    • Сумма трёх аргументов
    • Ноль, какими бы ни были аргументы
    • Как у аргумента, который реально совпал
  2. Что выбирает .card:has(> img)?
    • Изображения, которые являются прямыми потомками карточки
    • Карточки, содержащие изображение как прямого потомка
    • Карточки, расположенные после изображения в DOM
    • Все изображения, являющиеся потомками карточек
  3. В списке, где класс .visible есть только у части элементов li, что делает li:nth-child(2n of .visible)?
    • Он выбирает чётные li списка, у которых вдобавок есть класс .visible
    • Он выбирает каждый второй li, считая только элементы li.visible
    • Он выбирает чётные li, а затем добавляет им класс .visible