Меня зовут София. Я - CSS инженер. Это мой блог.

Если вам очень больно без стилей, вы можете их.

Простая семантичная карточка-ссылка

Постановка задачи

Представим себе элемент дизайна - карточку. Карточку товара, или карточку поста в блоге. Суть в том, что по клику в любое место карточки нужно переходить на страницу этого товара или поста.

Первая реализация

Логично предположить, что этот элемент должен быть сделан тегом a. Как-то так:

<a href="/item">
    <h3>Item header</h3>
    <p>Item looong description</p>
    <img src="/item_img.png"/>
</a>

Проблема

Во-первых это не семантично. Ссылка предполагает наличие внутри себя текста, который описывает, куда она ведет. Помещать туда что-то кроме него - значит путать пользователей со скринридерами и поисковых роботов.

Во-вторых внутри карточки могут предполагаться другие ссылки. Например, на автора статьи или категорию товара:

<a href="/item">
    <h3>Item header</h3>
    <p>Item looong description</p>
    <a href="/author">Ivan Ivanovich</a>
    <img src="/item_img.png"/>
</a>

Такая верстка не будет работать. Ссылки нельзя вкладывать внутрь других ссылок. Поведение в таком случае не определено, поэтому браузеры избегают такой верстки и превращают ее в такую:

<a href="/item">
    <h3>Item header</h3>
    <p>Item looong description</p>
</a><a href="/author">Ivan Ivanovich</a>
<img src="/item_img.png" />

Реализация получше

Все же стоит сделать карточку подходящим для нее тегом, в данном случае article, а главную ссылку положить в заголовок:

<article>
    <h3><a href="/item">Item header</a></h3>
    <p>Item looong description</p>
    <img src="/item_img.png"/>
</article>

Теперь верстка семантична и будет нормально прочитана скринридерами, роботами и другими разработчиками.

Как же сделать переход по ссылке по клику в любое место (кроме ссылки на автора), а не только в заголовок? Существует неочевидное решение на CSS для таких случаев.

<article>
    <h3><a href="/item">Item header</a></h3>
    <p>Item looong description</p>
    <img src="/item_img.png"/>
</article>

<style>

article {
    position: relative;
}

h3 > a::before {
    position: absolute;
    content: '';
    inset: 0;
}
</style>

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

"Вложенные" ссылки

Чтобы сделать внутри этой карточки ссылку на автора или категорию товара, положим нужные элементы поверх псевдо-элемента ссылки. Или же опустим псевдо под другие элементы. Значит нужно свойство z-index для управления контекстом наложения и pointer-events для управления событием клика.

<article>
    <h3><a href="/item">Item header</a></h3>
    <p>Item looong description</p>
    <a href="/author">Ivan Ivanovich</a>
    <img src="/item_img.png"/>
</article>

<style>

article {
    position: relative;
    z-index: 0;
}

h3 > a::before{
    position: absolute;
    content: '';
    inset: 0;
    z-index: -1;
}

p, img {
    pointer-events: none;
}
</style>

Разберем:

Более сложные ховер-эффекты

В примере выше по наведению мыши мы только меняем цвет текста для заголовка-ссылки. Это сделано с помощью псевдокласса :hover на теге a. Что делать, если по ховеру нам нужно менять цвет фона карточки?

Первая мысль: сделать селектор article:hover и в нем прописать новый цвет фона.

Почему это плохо? Bo-первых, потому что этот псевдокласс предназначен для интерактивных элементов. article не интерактивный. Во-вторых, этот эффект будет срабатывать, когда пользователь наводит мышку на "вложенные" ссылки. А должен только при наведении на "главную" ссылку.

Правильнее будет использовать функциональный псевдокласс :has()и написать так:

article:has(h3 > a:hover) {
    background-color: var(--hover-bg);
}

От такого решение нас пока останавливает только поддержка :has() в браузерах 😦

Поэтому используем article:hover, но помним, что это не очень правильное решение.

Нерешенные проблемы

Это решение не идеальное с точки зрения UX. Например, нельзя выделить текст в карточке, не зажав кнопку Alt (option на MacOS). Эта проблема осталась нерешенной.