Использование :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;
}