Изменяем поведение элементов при наличии точного указателя
Предположим, нам нужно сверстать накладывающиеся друг на друга элементы, которые будут полностью отображаться при наведении. Когда у нас есть курсор, мы без проблем можем навести его на элемент, и при срабатывании события hover, мы отображаем элемент.
Но на сенсорных экранах у нас нет такого точного указателя, как курсор, и даже если срабатывает событие наведения :hover
, то эффект остаётся и после того, как мы уберем палец/стилус с элемента, и будет сохранятся до тех пор, пока не произойдёт другое событие. Это некорректное поведение и может запутать пользователя.
На данный момент, есть специальные @media
запросы, которые определяют наличие точного указателя, и в статье мы рассмотрим один из вариантов их применения для решения вышеописаной проблемы
Немного теории
Так как сам только исследую эту тему, приведу несколько ссылок на которые я опирался, при написании этого раздела:
Understanding Success Criterion 2.5.6: Concurrent Input Mechanisms
Для начала определимся, что у каждого устройства может быть как основное(первичное) устройство ввода, так и второстепенные, и их может быть несколько. Например у ноутбука есть touchpad и клавиатура, можно дополнительно подключить мышь и еще клавиатуру, а также может быть и сенсорный экран. К планшету/смартфону также можно подключить дополнительные устройства ввода
Устройства ввода могут быть точными указателями, как курсор мыши, и могут быть неточными, как касание сенсорного экрана пальцем/стилусом
Перейдём к @media запросам - итак, в нашем распоряжении четыре @media
запроса - pointer
, hover
, any-pointer
, any-hover
В чем их отличие?
@media
запросы pointer
и hover
опираются только на основное(первичное) устройство ввода. Так как мы не хотим ограничивать пользователя единственным способом ввода, мы будем использовать другие @media
запросы
@media
запрос any-pointer
будет выполнен, если хотя бы одно устройство ввода имеет точный указатель
@media
запрос any-hover
будет выполнены если хотя бы одно устройство ввода имеет возможность наведения, то есть может “повиснуть” над элементом, не производя над ним никаких других манипуляций
any-pointer
имеет следующие значения
none
- указатель отсутствуетcoarse
- есть хотя бы один указатель ограниченной точностиfine
- есть хотя бы один точный указатель
any-hover
имеет следующие значения
none
- нет устройств ввода, которые имеют возможность наведенияhover
- есть хотя бы одно устройство ввода, которое имеет возможность наведения
Применение на практике
Применять эту возможность на практике можно в случаях, когда нужно или изменить внешний вид элемента, или его поведение в зависимости от устройства, на котором просматривается сайт
Для сенсорных экранов некоторые элементы можно делать больше по размеру, например область checkbox с галочкой. Такой checkbox будет доступней для пользователя на устройствах без курсора или другого точного устройства ввода
Теперь рассмотрим пример, который был описан в начале статьи.
Структура примера
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Practice</title>
<link rel="stylesheet" href="css/bootstrap-reboot.min.css"/>
<link rel="stylesheet" href="css/main.css"/>
</head>
<body>
<section class="section">
<div class="container">
<div class="section__grid grid">
<div class="grid__items">
<div class="grid__item"><img src="https://picsum.photos/256/256" alt=""/></div>
<div class="grid__item"><img src="https://picsum.photos/256/257" alt=""/></div>
<div class="grid__item"><img src="https://picsum.photos/256/258" alt=""/></div>
<div class="grid__item"><img src="https://picsum.photos/256/259" alt=""/></div>
<div class="grid__item"><img src="https://picsum.photos/256/260" alt=""/></div>
<div class="grid__item"><img src="https://picsum.photos/256/261" alt=""/></div>
</div>
</div>
</div>
</section>
</body>
</html>
Суть будет в следующем - изначально будем отображать все карточки целиком, а если устройство имеет хотя бы одно устройтво с точным указателем и имеет возможность наведения, то накладываем карточки друг на друга, и при наведении будем отображать необходимый элемент
Пишем стили для устройств, которые не имеют точного указателя, то есть изначально элементы будут отображены полностью, никакого дополнительного поведения у элементов пока не будет
.container {
max-width: 1120px;
padding: 0 16px;
margin: 0 auto;
}
.section {
padding: 64px 0;
--color: #f7f3f3;
background: var(--color);
min-height: 100vh;
}
.grid {
position: relative;
}
.grid__items {
overflow-x: auto;
display: flex;
position: relative;
}
.grid__item {
height: 128px;
width: 128px;
border-radius: 50%;
background: var(--color);
border: 2px solid #000;
transition: 0.4s;
overflow: hidden;
position: relative;
flex-shrink: 0;
}
.grid__item:not(:first-child) {
margin-left: -1.4em;
}
.grid__item img {
display: block;
width: 100%;
height: 100%;
-o-object-fit: cover;
object-fit: cover;
transition: 0.4s;
transform: scale(1.2);
}
Чтобы добавить элементам дополнительное поведение для устройств с точным указателем и с возможностью наведения на элемент, будем использовать комбинацию @media
запросов
Добавим следующие стили
@media (any-pointer: fine) and (any-hover: hover) {
.grid__item:not(:first-child) {
margin-left: -4.4em;
}
.grid__item:hover img {
transform: scale(1.2) translateX(-8%);
}
.grid__item:hover + * {
margin-left: -1.4em;
}
}
Посмотрим результат и разницу отображения и поведения на видео
Итоги
Если до этого мы в основном ориентировались только на разрешение устройства, и в зависимости от этого меняли внешний вид или поведение элементов, то теперь можно ориентироваться на возможности взаимодействия пользователя с устройством
Буду рад, если статья оказалась полезной
Спасибо за ваше внимание и уделённое время!