Создание анимированных кликабельных карточек с помощью :has() реляционного псевдокласса PlatoBlockchain Data Intelligence. Вертикальный поиск. Ай.

Создание анимированных кликабельных карточек с помощью реляционного псевдокласса :has()

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() там, чтобы преодолеть ограничения анимации этого подхода.

Начнем с разметки:

Fluffy gray and white tabby kitten snuggled up in a ball.

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 с пометкой).

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

Есть некоторые другие примеры вы хотите поделиться? Другие решения или идеи более чем приветствуются в разделе комментариев.

Отметка времени:

Больше от CSS хитрости