Создать карточку

Обзор

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

Правила

Выберите семантику для контента и взаимодействия с ним по отдельности:

  • используйте <article> в качестве корневого элемента карточки, независимо от того, ведет ли он на целевую страницу;
  • используйте нативную ссылку для навигации. Если вся карточка является одной целевой страницей, то одна ссылка может содержать <article>, только если карточка не содержит других интерактивных элементов (a, button, input, select, textarea).
  • сохраняйте ссылки и кнопки для независимых действий в виде отдельных нативных элементов управления;
  • используйте переключатель или флажок со связанным элементом <label> или option в нативном элементе <select>, если карточка представляет собой вариант выбора.

Медиаконтент, заголовок, дополнительный контент и действия должны быть расположены в логичном порядке. Не используйте свойство CSS order, чтобы изменить его (см. статью Макеты CSS и адаптивный дизайн).

Реализация

Используйте минимальную разметку и позвольте селекторам CSS распознавать каждый регион, чтобы простые карточки оставались простыми, а более насыщенные карточки оставались возможными. Карточка может содержать до четырех областей, перечисленных ниже в порядке их расположения в исходном коде. Любую из них можно опустить. Регионы являются прямыми дочерними элементами карточки и не группируются в элементы-оболочки, такие как .card__body, что не позволяет размещать и стилизовать регионы по селектору. Регион с одним элементом – это сам элемент, не заключенный в оболочку: отдельный абзац – это <p>. Используйте обертку, только если в регионе несколько элементов.

  • Медиаконтент. Первым дочерним элементом должен быть <img>, <picture>, <video> или <svg>. Добавляйте класс .media только к произвольному главному контенту, который не является одним из этих элементов, и никогда не помещайте простой элемент <img> в элемент .media.
  • Заголовок – заголовок, который не является частью другого элемента. Используйте <hgroup>, только если у заголовка есть подзаголовок или слоган, и <header>, если в разделе есть не только заголовок, но и, например, поле автора или значок. Если у карточки есть основная целевая страница, ссылка на нее добавляется в заголовок.
  • Контент. Отдельный элемент <p>, <ul> или <dl>. Если контент состоит из нескольких элементов, например нескольких абзацев или абзаца и списка, сгруппируйте их в одном элементе <div>, чтобы область была одним элементом сетки.
  • Нижний колонтитул – элемент <footer>, содержащий независимые действия в виде нативных ссылок и кнопок. Ссылка "Подробнее" может вести на тот же URL, что и ссылка в заголовке, но у нее должно быть описательное доступное название, которое начинается с видимого текста и содержит визуально скрытый текст (например, Read more<span> about poached eggs</span>), поскольку одинаковые ссылки "Подробнее" в списке ссылок программы чтения с экрана могут запутать пользователя. Не добавляйте другие ссылки в нижний колонтитул, которые повторяют URL заголовка.

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

Для изображений или видео, которые должны заполнять область с фиксированным соотношением сторон, задайте aspect-ratio и object-fit: cover для самого элемента <img> или <video>, чтобы он заполнял область без искажений (может произойти кадрирование). Используйте aspect-ratio контейнера .media только для другого главного контента. В противном случае сохраняется исходное соотношение сторон. Добавляйте к информативным изображениям подходящий альтернативный текст, а к декоративным – атрибут alt="".

Адаптация к доступному пространству

Основывайте макет на доступном пространстве карточки, а не на области просмотра. Чтобы адаптировать дочерние элементы карточки (медиа, текст, действия), сделайте карточку контейнером размера (container-type: inline-size) и напишите правила @container для ее дочерних элементов. Не задавайте размеры на основе родительского элемента сетки или списка. Фактическая ширина карточки может зависеть от количества столбцов, пробелов и т. д., что делает контрольные точки на основе родительского элемента неточными.

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

Выровнять карточки по сетке

Если карточки в строке должны иметь одинаковую высоту, используйте subgrid: сделайте так, чтобы каждая карточка занимала четыре общие строки (медиа, заголовок, контент, нижний колонтитул) и разместите области по селектору элементов, рассматривая все, что не является медиа, заголовком или <footer>, как контент. Если на карточке нет региона, его дорожка остается пустой, поэтому остальные регионы по-прежнему выстраиваются в линию с соседними карточками. Каждая дорожка содержит один элемент сетки, поэтому помещайте область контента в <div>, только если в ней больше одного элемента и карточки находятся на одной дорожке. Карточкам, которые не выровнены по соседним элементам, не нужны ни обертка, ни субсетка.

Модели взаимодействия

Карточки контента

Используйте <article> в качестве корневого элемента карточки. Ссылки и кнопки должны быть отдельными нативными элементами управления.

Карточки с одним пунктом назначения

Если вся карточка является одним целевым объектом и не содержит независимых действий, используйте одну нативную ссылку. Ссылка может быть обернута в <article>. Не вкладывайте в ссылку другие ссылки, кнопки или элементы управления формой. Текст "Читать далее" должен быть простым элементом <p> или <span>. Поскольку доступным названием ссылки является весь текст карточки, он должен быть коротким. Если в карточке много текста или других действий, используйте шаблон растянутой ссылки, чтобы ссылкой был только заголовок:

<a href="/recipes/poached-eggs">
  <article class="card">
    <h3>Poached eggs</h3>
    <p>Two poached eggs served on toasted sourdough.</p>
  </article>
</a>

Интерактивные карточки с независимыми действиями

Если нажатие на карточку запускает действие, а не переход, используйте <button> вместо ссылки.

Если карточка контента ссылается на основную целевую страницу, содержит другие интерактивные элементы и должна быть полностью кликабельной:

  • Используйте одно согласие на основной ссылке: добавьте .card-link только на одну ссылку в карточке (ссылку в заголовке). Нижний колонтитул и другие ссылки не должны получать этот класс, иначе каждый из них будет растягивать свой оверлей, а последний захватит всю карточку.
  • Добавьте ссылку в заголовок и растяните область нажатия указателя на всю карточку с помощью ::after.
.card:has(a.card-link) {
    position: relative;
}

.card a.card-link::after {
    content: "";
    position: absolute;
    inset: 0;
}
  • Выделите интерактивные элементы с помощью position: relative; z-index: 1, чтобы они оставались доступными. Настройте таргетинг на типы элементов (например, a, button), а не на классы.
  • НЕ применяйте z-index ко всему контейнеру, иначе он будет регистрировать события указателя, которые не приводят к каким-либо действиям.
.card:has(a.card-link) {
    /* Keep other interactive elements above the overlay */
    a:not(.card-link), button, input, x-button {
        position: relative;
        z-index: 1;
    }
}
  • Стилизуйте саму карточку при наведении/фокусе, а не растянутую ссылку:
.card {
    a.card-link {
        &:focus-visible {
            outline: none; /* Draw it on the card instead */
        }
    }
    
    &:has(a.card-link:focus-visible) {
        /* Focus ring */
    }

    &:has(a.card-link:hover) {
        /* Hover styles */
    }
}

Карточки выбора

Для карточек, представляющих предопределенные варианты выбора, используйте <label class="card"> с флажком или переключателем в качестве прямого дочернего элемента.

Оформить выбранную карточку с помощью :has(:checked). Никогда не меняйте свойства, влияющие на макет, такие как border-width, padding или font-weight, при выборе, потому что карточка и соседние с ней элементы будут прыгать. Выделите карточку с помощью outline, box-shadow или прозрачной границы, которая меняет только цвет:

.card {
  border: 2px solid transparent;

  &:has(> :checked) {
    border-color: var(--accent);
  }
}

Видимый флажок или переключатель сам по себе является нецветным индикатором выбора, поэтому достаточно только изменения цвета. Если элемент управления визуально скрыт (оставьте его доступным для фокусировки и в дереве специальных возможностей, никогда не используйте display: none), добавьте бесцветный индикатор, который не влияет на макет, например значок галочки или более толстую outline.

Если варианты выбора находятся в раскрывающемся списке, элементы которого оформлены в виде карточек, используйте стандартный элемент <select> с appearance: base-select и стилизуйте элементы ::picker(select) и <option>, а не заменяйте элемент select карточками <div>. Подробную информацию и резервные варианты можно найти в разделе Специальные макеты для выбора.