Есть распространённый паттерн карточки товара, статьи и так далее. Обычно это картинка, заголовок, ссылка и дополнительные элементы. Верстают их по-разному, но в целом выработан паттерн, который выглядит примерно так:
<article>
<img src="..." alt="">
<h3>
<a href="/catalog/76345865">Title</a>
</h3>
<p>99$</p>
<p>Description</p>
<a href="/cart/add/76345865">Add to cart</a>
</article>
Хочется, чтобы при клике в любое место карточки открывалась детальная страница. Пользователи привыкли к этому. В примере попасть на детальную страницу можно только кликнув по заголовку. Фикс часто сводится к оборачиванию всего ссылкой. Спецификация HTML допускает размещение внутри ссылки того, что можно размещать в её родителе.
Но внутри интерактивных элементов нельзя размещать другие интерактивные элементы. В примере это “Add to cart”. Вложенные интерактивные элементы приводят к плохому пользовательскому опыту и проблемам с доступностью. Кроме того, весь текстовый контент ссылки становится её доступным именем, что крайне избыточно. Иногда от ссылки отказываются, меняя на
<div> с обработчиками кликов. Тоже плохо.Хейдон Пикеринг предложил компромиссное решение. Если кратко, то ссылка остаётся внутри заголовка. К ней добавляется псевдо-элемент
::before и растягивается на всю карточку. Другие интерактивные элементы поднимаются на слой выше, чем ::before. Клик по псевдо-элементу делегируется ссылке и всё работает.Паттерн рабочий, я им пользуюсь, но есть неудобства. Нужно добавлять
::before, работать с position: absolute и z-index, не забыть поднять другие интерактивные элементы выше, правильно настроить рамку фокуса и т.д.Группа OpenUI поделилась идеями по улучшению и выпустила предложение Link Area Delegation. Суть сводится к тому, чтобы предоставить декларативный механизм делегирования кликов с других элементов на ссылку. Предложено несколько вариантов, которые ещё будут прорабатываться.
Вариант 1: атрибуты
<article linkarea>
...
<h3>
<a href="/catalog/76345865" defaultlink>Title</a>
</h3>
...
</article>
<article linkarea="link_id">
...
<h3>
<a href="/catalog/76345865" id="link_id">Title</a>
</h3>
...
<a href="/cart/add/76345865">Add to cart</a>
</article>
Клик по элементу с атрибутом
linkarea делегируется ссылке с атрибутом defaultlink или ссылке, id которой указан в атрибуте linkarea.Вариант 2: новый элемент
<article>
<linkarea>
...
<h3>
<a href="/catalog/76345865" defaultlink>Title</a>
</h3>
...
<a href="/cart/add/76345865">Add to cart</a>
</linkarea>
</article>
Вместо атрибута предлагается элемент
<linkarea>. Клики по нему делегируются ссылке с атрибутом defaultlink. Это менее удобно, не всегда можно что-то обернуть, например, строку таблицы, у которой жёсткие правила вложенности.Вариант 3: CSS вместо HTML
<article class="card">
...
<h3>
<a href="/catalog/76345865">Title</a>
</h3>
...
<a href="/cart/add/76345865">Add to cart</a>
</article>
<style>
.card {
pointer-area: contain;
}
.card h3 a {
pointer-area: expand;
}
</style>
Первая ссылка внутри карточки расширяет (
pointer-area: expand) свою область клика на элемент, который содержит (pointer-area: contain) расширяемый элемент.Вариант 4: использование Invokers
<article commandfor="link_id" commands="click contextmenu">
...
<h3>
<a href="/catalog/76345865" id="link_id">Title</a>
</h3>
...
<a href="/cart/add/76345865">Add to cart</a>
</article>
Invokers — это декларативный механизм добавления действий к элементам. Я делал пост с обзором ранней версии этого предложения. Частично Invokers уже реализованы в Chrome Canary, Firefox Nightly и Safari TP. В ближайшем будущем стоит ожидать полноценного внедрения в стабильные браузеры.
Я думаю, что у четвёртого варианта больше всего шансов на реализацию. Нужно будет расширить API, которое уже внедряется в браузеры. Но идеи ещё будут обсуждаться и возможны изменения. В целом предложение звучит круто и полезно.