Приветствую. Представляю вашему вниманию перевод заметки «Detecting Hover-Capable Devices», опубликованной 30 июня 2021 года автором Michelle Barker
К сожалению, поискать на Habr более ранние материалы на аналогичную тему я додумался лишь после публикации. Нашёл качественную статью "Выявление устройств с сенсорными экранами на чистом CSS". А текущую заметку предлагаю считать дополнительным напоминанием о существовании технологии и повторением пройденного.
Сейчас, когда количество устройств стало бо́льшим, чем когда-либо прежде, мы, разработчики, больше не можем полагаться на область видимости, как единственный фактор, определяющий стилизацию сайта. До недавнего времени мы могли отталкиваться от размера устройства: например, считая, что на мобильных устройствах используется сенсорный ввод, а на устройствах с большим экраном — мышь. И на этом основании с помощь медиазапроса определить вариант стилизации содержимого:
.some-component {
/* Styles for touch devices */
}
@media screen and (min-width: 1024px) {
.some-component {
/* Styles for hover-able devices */
}
}
Но на сегодняшний день это не очень-то помогает. В современном IPad разрешение экрана может быть больше, чем у бюджетного ноутбука. Или, например, кто-то может использовать свой планшет как дополнительный монитор — имея в этом случае возможность наводить указатель на элементы. Но в приведённых выше медиазапросах устройства ввода никак не учитываются.
В наши дни к определению устройства пользователя нужно подходить более тщательно. К счастью, некоторые новые медиазапросы служат как раз для этой цели.
Медиазапросы 5 уровня
Помимо уже знакомых медиазапросов, позволяющих определять размер области видимости, спецификация CSS Level 5 Media Queries привнесла новые. Один из них позволяет определить, поддерживает ли основное указывающее устройство пользователя возмжоность наведения (hover). Допустимым является значение hover
(будет true
для таких устройств, как, например, мышь) и значение none
(будет true
для планшетов с сенсорными экранами). Использовать данный медиазапрос мы можем следующим образом:
.some-component {
/* Styles for touch devices */
}
@media (hover: hover) {
.some-component {
/* Styles for hover-able devices */
}
}
Уточнение: На самом деле, функционал
hover
иpointer
является частью спецификации медиазапросов ещё с 4 уровня. Но лишь недавно стали поддерживаться почти всеми браузерами.
Данный пример корректно работает в большинстве браузеров, за исключением некоторых версий Android, которые имеют функционал, позволяющий имитировать hover
долгим нажатием, из-за чего такие устройства могут быть распознаны как поддерживающие наведение. Если мы хотим показывать этим пользователям те же стили, что и на других сенсорных устройствах, нужно сделать дополнительный запрос.
Pointer
Функционал pointer
проверяет наличие и точность указывающего устройства. Допустимыми являются значения coarse
(для таких указателей, как палец при использовании устройств с сенсорным экраном), fine
(например, для мыши) и none
(устройство без указателя).
Добавление этого условия к нашему медиазапросу успешно определяет сенсорный ввод на Android-устройствах:
.some-component {
/* Styles for touch devices, including Android */
}
@media (hover: hover) and (pointer: fine) {
.some-component {
/* Styles for hover-able devices */
}
}
any-hover и any-pointer
Если перечисленного недостаточно, условия any-hover
и any-pointer
позволяют включать в проверку возможности не только основного, но и любого другого подключённого указывающего устройства. Следовательно, если у вас есть устройство с подключёнными и мышью и сенсорным экраном, запрос any-hover: hover
будет true
.
Мне пока что не приходилось применять данный функционал, но спецификация включает несколько примеров того, как он может использоваться.
Пример JavaScript
Недавно я сделал страничку с тремя одинаковыми изображениями, каждое из которых является ссылкой. При наведении курсора на эту ссылку-изображение, подобно всплывающей подсказке, показывается его имя. Но пользователи устройств с сенсорным экраном увидеть подсказку не смогут. Вместо этого, при нажатии сразу будет совершён переход по ссылке, что может раздражать, так как пользователи заранее не знают, куда именно попадут. Именно поэтому я решил при клике не осуществлять переход сразу, а лишь при нажатии на появившуюся дополнительную кнопку. Мы можем использовать тот же медиазапрос для определения устройства с сенсорным экраном в JS, используя matchMedia
:
const list = document.querySelector('[data-list]')
const isHoverableDevice = window.matchMedia(
'(hover: hover) and (pointer: fine)'
)
/* Hide the block link initially */
blockLink.hidden = true
list.addEventListener('click', (e) => {
/* Do nothing if target is not a link, or device is hover-capable */
if (!e.target.dataset.link || isHoverableDevice.matches) return
/* If touch device, show the block link */
e.preventDefault()
blockLink.hidden = false
blockLink.innerText = `Visit ${e.target.dataset.link}’s page`
blockLink.setAttribute('href', e.target.href)
})
Результат:
Доступность
В зависимости от интерфейса, мы можем помочь вспомогательным технологиям, используя атрибуты ARIA, чтобы объявить кнопку, когда произойдут изменения, или переместить на кнопку внимание пользователя. Данный пример с MDN включает демонстрацию того, как использовать ARIA Live Regions для объявления динамических изменений элемента.
Поддержка браузерами
Отличная новость в том, что вы можете использовать эти медиазапросы уже сейчас, поскольку они поддерживаются всеми современными браузерами. Теперь вы можете улучшить удобство для пользователей любых устройств.