Ссылки нестандартной формы с помощью подсетки

Ссылки нестандартной формы с помощью подсетки

От автора: пользовательские интерфейсы на основе карточек — это часто используемые шаблоны веб-дизайна, и нет ничего необычного в создании макета, который требует применения эффекта наведения (или выделения фокусом) для всей карточки. Есть несколько стратегий для реализации этого эффекта с помощью CSS.

Но что, если наш эффект наведения ссылок должен влиять на ряд дочерних элементов, и не все они расположены точно внутри прямоугольника, как обычная карточка?

С помощью CSS Grid мы можем размещать элементы по горизонтальной и вертикальной оси, чтобы создавать визуально интересные макеты, как этот:

Ссылки нестандартной формы с помощью подсетки

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

Ссылки нестандартной формы с помощью подсетки

Если в дизайне пользовательского интерфейса эти элементы сетки должны действовать как ссылки, то имеет смысл применить эффект наведения ко всем элементам сетки при наведении один из них.

Ссылки нестандартной формы с помощью подсетки

Наведение курсора на один элемент вызывает эффект наведения на оба

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

.grid__img:hover ~ .grid__caption,
.grid__img:focus ~ .grid__caption { /* Hover and focus styles */
}

Но, к сожалению, общий комбинатор смежных элементов выделяет только последующие элементы, а не на предыдущие. Если навести курсор на второй элемент, эффект наведения не будет применен к первому элементу.

Абсолютное позиционирование

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

<div class="grid"> <a href="/" class="grid__link"></a> <div class="grid__img"> <img src="..." alt="" /> </div> <div class="grid__card"> <h2>Eu scelerisque felis</h2> <p> Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris ni ut aliquip ex ea commodo consequat. </p> <span>Read more→</span> </div>
</div>

.grid { position: relative; display: grid; grid-template: repeat(3, 1fr) / repeat(3, 1fr);
} .grid__link { position: absolute; display: grid; grid-template: repeat(3, 1fr) / repeat(3, 1fr);
}

Позиционирование с помощью сетки

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

.grid__link { grid-area: 1 / 1 / -1 / -1; display: grid; grid-template: repeat(3, 1fr) / repeat(3, 1fr); z-index: 1;
}

Использование отрицательных линий сетки — удобный способ позиционирования элемента от первой до последней линии — при условии, что мы используем явные треки, а не неявные.

Доступность

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

Используя aria-labelledby, мы можем задать нашей ссылке доступную метку, которая соответствует заголовку компонента. Мы также можем использовать aria-hidden, чтобы заголовок не был объявлен во второй раз.

<div class="grid"> <a href="/" class="link" aria-labelledby="title"></a> <div class="grid__img"> <img src="..." alt="" /> </div> <div class="grid__card"> <h2 id="title" aria-hidden="true">Eu scelerisque felis</h2> <p> Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. </p> <span>Read more→</span> </div>
</div>

Это работает правильно при тестировании с использованием VoiceOver в Safari.

Но… это не решает проблему

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

Ссылки нестандартной формы с помощью подсетки

Когда указатель находится где-то над фиолетовой областью, ссылка будет выделяться

На самом деле мы хотим, чтобы ссылка работала так, как если бы она имела такую форму:

Ссылки нестандартной формы с помощью подсетки

Для пользователя было бы лучше, если бы только фиолетовая область, показанная здесь, активировала эффект наведения

Вложенные сетки приходят на помощь

Теперь мы рассмотрим еще одну причину, по которой CSS Grid является идеальным выбором для размещения этого компонента. Сделав ссылку с абсолютным позиционированием контейнером сетки, который соответствует сетке компонента, мы можем наложить элементы сетки с помощью псевдо-элементов. Если мы добавим к самой ссылке pointer-events: none и pointer-events: auto к псевдоэлементам, эффект наведения будет применен только тогда, когда курсор наведен на эти области.

.grid__link { pointer-events: none;
} .grid__link::before,
.grid__link::after { pointer-events: auto;
}

Несовершенное решение

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

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

Лучшее решение с помощью подсетки

Здесь в игру вступает подсетка. Подсетка является частью спецификации CSS Grid Level 2. Она позволяет нам создать контейнер сетки внутри родительской сетки, которая наследует родительскую сетку по оси колонок или рядов (или и то, и другое).

Мы можем, в свою очередь, сделать эту ссылку сеткой, как и раньше, но на этот раз мы можем использовать grid-template (или условное обозначение grid-template-rows / grid-template-columns), чтобы указать ему использовать подсетку.

.link { grid-template: subgrid / subgrid;
}

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

Поддержка браузерами

Прежде чем мы начнем радоваться, давайте посмотрим на реальность. На момент написания, подсетка поддерживается только в Firefox. И все. Это позор, потому что она чрезвычайно полезна и, вероятно, расширит использование CSS Grid. Как только она будет реализована в Chrome (и я верю, что в какой-то момент это произойдет), тогда ее будет гораздо выгоднее использовать в производстве. Я надеюсь, что написание и применение таких вариантов использования может дать импульс для обеспечения поддержки подсеток во всех браузерах.

Если вы хотите использовать вышеописанную технику, вы всегда можете предоставить резервный (хотя и менее совершенный) вариант для не поддерживающих браузеров, который, к счастью, представляет собой только одну строку кода:

.link { grid-template: repeat(3, 1fr) / repeat(3, 1fr); @supports (grid-template: subgrid / subgrid) { grid-template: subgrid / subgrid; }
}

Затем, когда подсетка наконец попадет в мейнстрим, ваш сайт будет готов к работе! Смотрите полную демонстрацию на Codepen:

Автор: Michelle Barker

Источник: https://css-irl.info

Редакция: Команда webformyself.