DevGang
Авторизоваться

Использование :has в качестве селектора предыдущих родственных элементов

На этой неделе я очень обрадовался, когда наконец-то использовал :has. Проблема с ним заключалась в поддержке браузерами, которая пока недостаточно высока, чтобы использовать его в производственном коде. В частности, в Firefox его не будет до 121 версии (наконец-то!), а это мой любимый браузер...

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

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

Сложность заключается в том, что по умолчанию все ссылки должны иметь непрозрачность 1 и меняться только при наведении курсора на другую ссылку.

HTML

Вот HTML, который я создал для примера:

<ul>
  <li><a href="#">One</a></li>
  <li><a href="#">Two</a></li>
  <li><a href="#">Three</a></li>
  <li><a href="#">Four</a></li>
  <li><a href="#">Five</a></li>
  <li><a href="#">Six</a></li>
</ul>

Другой селектор родственных элементов

Поскольку ссылка является дочерней по отношению к элементу списка, самое простое, что можно сделать, это навести курсор на элемент списка. Если я навожу курсос на ссылку, то по определению я навожу курсос на родительский элемент ссылки.

Нацеливание на родственные элементы, которые идут после элемента, на который мы наводим курсор, очень просто:

li:hover ~ li {
  opacity: 0.5;
}

Чтобы сделать то же самое для родственных элементов, которые идут до того, на котором мы зависнем, нужно использовать :has и фактически написать то же самое, но в обратном порядке:

li:has(~ li:hover) {
  opacity: 0.5;
}

Это так странно читать.

В первом фрагменте говорится: Примените CSS к любому li, который является (следующим) родственным элементом того, на который наведен курсор.

Во втором фрагменте говорится: Применить CSS к любому li, у которого есть (следующий) родственный элемент, на который наведен курсор.

Фокусирование

Применять что-то при наведении - это хорошо, но что, если вы хотите, чтобы оно всегда применялось при фокусировке? Здесь мы можем использовать focus-within: так что если что-то внутри li имеет фокус, примените CSS. У li не может быть фокуса (если только вы не добавите к нему tabindex), и ссылка - единственная вещь внутри него, которая может быть сфокусирована.

li:hover ~ li,
li:has(~ li:hover),
li:focus-within ~ li,
li:has(~ li:focus-within) {
  opacity: 0.5;
}

Все просто - это тот же код, но с использованием focus-within вместо hover.

Есть проблема, когда одна из ссылок имеет фокус, но вы наводите курсор на другую: все становится немного прозрачным. Но спорно, сколько пользователей будут это делать? Также спорно, нужен ли вам тот же эффект при focus-within, когда ссылка, на которой вы сфокусировались, имеет контур вокруг себя?

Итоговый код

Вот весь код в HTML:

<ul>
  <li><a href="#">One</a></li>
  <li><a href="#">Two</a></li>
  <li><a href="#">Three</a></li>
  <li><a href="#">Four</a></li>
  <li><a href="#">Five</a></li>
  <li><a href="#">Six</a></li>
</ul>

И в CSS:

body{
  font-size: 1.5rem;
}

li {
  padding-block: 0.5em;
}

li:hover ~ li,
li:has(~ li:hover),
li:focus-within ~ li,
li:has(~ li:focus-within) {
  opacity: 0.5;
}

Источник:

#CSS #HTML
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться