CSS :has()
псевдокласс развертывается во многих браузерах с Chrome и Safari
уже полностью поддерживает его. Его часто называют «родительским селектором» — например, мы можем выбрать стиль родительского элемента из дочернего селектора — но это гораздо больше, чем :has()
может помочь нам решить. Одной из таких вещей является повторное изобретение интерактивного шаблона карт, который многие из нас любят время от времени использовать.
Мы посмотрим, как :has()
может помочь нам справиться со связанными картами, но сначала…
:has()
псевдокласс?
Что это Уже есть связка of большой сообщений плавающий вокруг которые отлично объясняют, что :has()
и для чего он используется, но он все еще достаточно нов, чтобы мы могли сказать о нем несколько слов и здесь.
:has()
реляционный псевдокласс, являющийся частью Рабочий проект селекторов W3C уровня 4. Вот для чего нужны скобки: сопоставление элементов, которые связаны с определенными дочерними элементами или, точнее, содержат их.
/* Matches an article element that contains an image element */
article:has(img) { }
/* Matches an article element with an image contained immediately within it */
article:has(> img) { }
Итак, вы можете понять, почему мы могли бы назвать его «родительским» селектором. Но мы также можем комбинировать его с другими функциональными псевдоклассами, чтобы получить более конкретную информацию. Допустим, мы хотим стилизовать статьи, которые не содержать любые изображения. Мы можем комбинировать относительные силы :has()
с отрицательными способностями :not()
для этого:
/* Matches an article without images */
article:not(:has(img)) { }
Но это только начало того, как мы можем объединить усилия, чтобы сделать больше с :has()
. Прежде чем мы перейдем непосредственно к решению загадки интерактивных карточек, давайте рассмотрим несколько способов, которыми мы в настоящее время подходим к ним, не используя :has()
.
Как мы в настоящее время обрабатываем кликабельные карточки
В наши дни существует три основных подхода к тому, как люди создают полностью интерактивную карточку, и чтобы полностью понять силу этого псевдокласса, было бы неплохо провести небольшой обзор.
Подход «Ссылка как оболочка»
Этот подход используется довольно часто. Я никогда не использую этот подход, но я создал короткую демонстрацию, чтобы продемонстрировать его:
Здесь есть много проблем, особенно когда речь идет о доступности. Когда пользователи перемещаются по вашему сайту, используя функция ротора, они услышат полный текст внутри этого элемент — заголовок, текст и ссылка. Кто-то может не захотеть высидеть все это. Мы можем сделать лучше. Начиная с HTML5, мы можем вкладывать блочные элементы внутрь
элемент. Но мне это никогда не кажется правильным, особенно по этой причине.
Плюсы:
- Быстро внедрить
- Семантически правильный
Минусы:
- Проблемы доступности
- Текст не выбирается
- Много хлопот, чтобы перезаписать стили, которые вы использовали в своих ссылках по умолчанию.
Метод JavaScript
С помощью JavaScript мы можем прикрепить ссылку к нашей карточке вместо того, чтобы писать ее в разметке. Я нашел эту замечательную демонстрацию CodePen от стоимость разработки который также сделал текст карты доступным для выбора в процессе:
Этот подход имеет много преимуществ. Наши ссылки доступны в фокусе, и мы даже можем выделить текст. Но есть некоторые недостатки, когда дело доходит до стиля. Например, если мы хотим оживить эти карты, нам нужно будет добавить :hover
стили на нашем основном .card
обертка вместо самой ссылки. Мы также не выиграем от анимации, когда ссылки находятся в фокусе от табуляции клавиатуры.
Плюсы:
- Можно сделать полностью доступным
- Возможность выделения текста
Минусы:
- Требуется JavaScript
- Щелчок правой кнопкой мыши невозможен (хотя это можно исправить с помощью дополнительных сценариев)
- Потребуется много стилей на самой карте, что не будет работать при фокусировке ссылки.
::after
селекторный подход
Ассоциация Этот метод требует, чтобы мы установили карту с относительным позиционированием, а затем установили абсолютное позиционирование для ссылки. ::after
псевдоселектор ссылки. Это не требует JavaScript и довольно легко реализуется:
Здесь есть несколько недостатков, особенно когда речь идет о выделении текста. Если вы не укажете более высокий z-индекс на теле карты, вы не сможете выбрать текст, но если вы это сделаете, имейте в виду, что щелчок по тексту не активирует вашу ссылку. Хотите ли вы выделяемый текст, зависит от вас. Я думаю, что это может быть проблема UX, но это зависит от варианта использования. Текст по-прежнему доступен для чтения с экрана, но моя главная проблема с этим методом заключается в отсутствии возможностей анимации.
Плюсы:
- Простота реализации
- Доступная ссылка без раздутого текста
- Работает при наведении и фокусе
Минусы:
- Текст не выбирается
- Вы можете анимировать только ссылку, поскольку это элемент, на который вы наводите курсор.
::after
:has()
Новый подход: использование Теперь, когда мы установили существующие подходы к кликабельным карточкам, я хочу показать, как ввести :has()
смесь решает большинство этих недостатков.
На самом деле, давайте основывать этот подход на последнем, который мы рассмотрели, используя ::after
на элементе ссылки. Мы действительно можем использовать :has()
там, чтобы преодолеть ограничения анимации этого подхода.
Начнем с разметки:
Some Heading
Curabitur convallis ac quam vitae laoreet. Nulla mauris ante, euismod sed lacus sit amet, congue bibendum eros. Etiam mattis lobortis porta. Vestibulum ultrices iaculis enim imperdiet egestas.
Я буду максимально упрощать работу, ориентируясь на элементы в CSS, а не на классы.
Для этой демонстрации мы добавим масштабирование изображения и тень к карточке при наведении, а также анимируем ссылку с всплывающей стрелкой и изменением цвета текста ссылки. Чтобы упростить эту задачу, мы добавим некоторые настраиваемые свойства для нашей карты. Вот базовый стиль:
/* The card element */
article {
--img-scale: 1.001;
--title-color: black;
--link-icon-translate: -20px;
--link-icon-opacity: 0;
position: relative;
border-radius: 16px;
box-shadow: none;
background: #fff;
transform-origin: center;
transition: all 0.4s ease-in-out;
overflow: hidden;
}
/* The link's ::after pseudo */
article a::after {
content: "";
position: absolute;
inset-block: 0;
inset-inline: 0;
cursor: pointer;
}
Большой! Мы добавили начальный масштаб для изображения (--img-scale: 1.001
), начальный цвет заголовка карточки (--title-color: black
) и некоторые дополнительные свойства, которые мы будем использовать, чтобы наша стрелка выскочила из ссылки. Мы также установили пустое состояние box-shadow
объявление, чтобы оживить его позже. Это устанавливает то, что нам нужно для интерактивной карты прямо сейчас, поэтому давайте добавим к ней некоторые сбросы и стили, добавив эти пользовательские свойства к элементам, которые мы хотим анимировать:
article h2 {
margin: 0 0 18px 0;
font-family: "Bebas Neue", cursive;
font-size: 1.9rem;
letter-spacing: 0.06em;
color: var(--title-color);
transition: color 0.3s ease-out;
}
article figure {
margin: 0;
padding: 0;
aspect-ratio: 16 / 9;
overflow: hidden;
}
article img {
max-width: 100%;
transform-origin: center;
transform: scale(var(--img-scale));
transition: transform 0.4s ease-in-out;
}
article a {
display: inline-flex;
align-items: center;
text-decoration: none;
color: #28666e;
}
article a:focus {
outline: 1px dotted #28666e;
}
article a .icon {
min-width: 24px;
width: 24px;
height: 24px;
margin-left: 5px;
transform: translateX(var(--link-icon-translate));
opacity: var(--link-icon-opacity);
transition: all 0.3s;
}
.article-body {
padding: 24px;
}
Давайте будем добрее к людям, а также добавим класс чтения с экрана скрыто за ссылкой:
.sr-only:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
Наша открытка начинает выглядеть довольно мило. Пришло время добавить к нему немного волшебства. С :has()
псевдокласса, теперь мы можем проверить, наведена ли наша ссылка или находится ли она в фокусе, затем обновить наши пользовательские свойства и добавить box-shadow
. С этим небольшим фрагментом CSS наша карточка действительно оживает:
/* Matches an article element that contains a hover or focus state */
article:has(:hover, :focus) {
--img-scale: 1.1;
--title-color: #28666e;
--link-icon-translate: 0;
--link-icon-opacity: 1;
box-shadow: rgba(0, 0, 0, 0.16) 0px 10px 36px 0px, rgba(0, 0, 0, 0.06) 0px 0px 0px 1px;
}
Видишь, что там? Теперь мы получаем обновленные стили, если любой дочерний элемент в карточке наведен или сфокусирован. И хотя элемент ссылки — единственное, что может содержать состояние наведения или фокуса в ::after
кликабельный карточный подход, мы можем использовать его, чтобы сопоставить родительский элемент и применить переходы.
И вот оно. Еще один мощный вариант использования :has()
селектор. Мы можем не только сопоставить родительский элемент, объявив другие элементы в качестве аргументов, но также можем использовать псевдоэлементы для сопоставления и стиля родителей.
Плюсы:
- Доступный
- Анимируемый
- JavaScript не требуется
- Пользы
:hover
на правильный элемент
Минусы:
- Текст не так легко выбрать.
- Поддержка браузеров ограничена Chrome и Safari (поддерживается в Firefox с пометкой).
Вот демонстрация использования этой техники. Вы можете заметить дополнительную обертку вокруг карты, но это я просто играю с контейнерные запросы, что является лишь одной из тех фантастических вещей, которые появляются во всех основных браузерах.
Есть некоторые другие примеры вы хотите поделиться? Другие решения или идеи более чем приветствуются в разделе комментариев.