События указателя и доступный ввод: мышь, сенсорный экран и перо
Создавайте надежные взаимодействия с указателем для мыши, сенсорного экрана и пера, сохраняя доступ с клавиатуры, удобные области нажатия и предсказуемую отмену.
Нужна структурированная документация по теме Платформа?
Эта статья относится к редакционной библиотеке. Для пошаговой настройки, справки и постоянных обновлений переходите сразу в соответствующий раздел docs.
Pointer Events предоставляет веб-приложению общую модель событий для ввода мышью, сенсорным экраном и пером. Такая общая модель упрощает организацию перетаскивания, рисования и прямого управления, но не делает все способы ввода взаимозаменяемыми. Надежный интерфейс рассматривает события указателя как один из способов взаимодействия, сохраняет возможность работы с клавиатуры, предусматривает удобные области нажатия и обрабатывает прерывания без потери состояния.
Важный вопрос проектирования состоит не в том, каким физическим устройством владеет человек. Важно, можно ли удобно выполнить текущее действие доступным ему способом ввода. В ходе одной задачи пользователь может переключаться между мышью, сенсорным экраном, пером, клавиатурой, голосовым управлением или вспомогательными технологиями. Страница должна реагировать на взаимодействие и его результат, а не пытаться составить профиль человека или устройства.
О связанных проверках приложений см. материалы о проверке взаимодействий в браузере и тестировании профилей устройств. Если рабочий процесс охватывает разные платформы, статья о кроссплатформенных профилях браузера рассказывает, как документировать ожидаемые различия.
Общая модель событий, а не классификатор устройств
Спецификация Pointer Events определяет события и интерфейсы для обработки ввода с помощью указывающих устройств независимо от конкретного устройства. В обычном коде приложения это означает, что для распространенных операций можно использовать pointerdown, pointermove, pointerup и pointercancel, а не поддерживать полностью отдельную логику для каждого источника ввода с указателем. Браузер предоставляет свойства текущего события указателя, включая его идентификатор и обобщенный тип указателя. Они помогают связывать события с активным взаимодействием, но не дают надежных оснований судить о личности, возможностях, владении устройством или намерениях человека.
У мыши, сенсорного ввода и пера разные физические особенности. У мыши обычно есть курсор и отдельные кнопки. Палец соприкасается с большей областью экрана и может также использоваться для жестов навигации в браузере. Перо позволяет точнее указывать на объекты и, если устройство это поддерживает, может иметь кнопки или свойства, связанные с нажимом. Пользователь также может подключить или отключить устройство ввода, пока страница открыта. Элементы управления следует делать понятными и работоспособными без предположения о неизменной конфигурации ввода.
Модель событий помогает объединять поведение, а не стирать полезные различия. У поверхности для рисования может быть особое поведение пера, если оно действительно нужно приложению, но обычная кнопка должна оставаться кнопкой. Перетаскивание за маркер не должно быть единственным способом переставить элементы списка, если можно предусмотреть доступный с клавиатуры вариант. Для меню не следует требовать наведения, недоступного при сенсорном вводе. Начните с задачи и ее результата, а затем выберите понятное взаимодействие с предусмотренным способом восстановления.
Рекомендация W3C Pointer Events уровня 3 служит нормативным источником сведений о модели событий и ее поведении. Руководство MDN по Pointer Events содержит практический обзор использования этих событий в веб-приложениях. Поддержка браузерами и детали реализации могут меняться, поэтому проверяйте актуальную совместимость именно тех событий и свойств, от которых зависит продукт. Не следует считать, что знакомое название API гарантирует одинаковое поведение во всех версиях браузеров или встроенных веб-представлениях.
Отслеживайте взаимодействие от начала до завершения
Событие pointerdown служит удобной отправной точкой взаимодействия. Оно сообщает странице, что указатель коснулся поверхности или иным образом начал действие ввода. При перетаскивании приложение может запомнить начальную точку, перемещаемый элемент и идентификатор текущего указателя. Инструмент рисования может начать штрих. Для пользовательского элемента управления можно зафиксировать возможное нажатие, отложив окончательное решение до завершения взаимодействия.
Поддерживать небольшое явное состояние взаимодействия безопаснее, чем воспринимать каждое событие как отдельную команду. Состояние может указывать, что перемещается определенный элемент, активен штрих или ожидается подтверждение нажатия. Оно также должно описывать, как его сбросить. Если пользователь прервал жест, перешел на другую страницу или браузер перехватил взаимодействие, элемент управления не должен навсегда остаться в нажатом состоянии, а индикатор перетаскивания не должен следовать за устаревшими координатами.
pointermove сообщает о перемещении указателя. Страница может использовать его, чтобы обновить предварительный просмотр, переместить выбранный объект или нарисовать штрих. События перемещения могут приходить часто, а платформа или браузер может объединять несколько отсчетов. Поэтому поведение приложения должно зависеть от текущего взаимодействия и его конечного результата, а не от предположения, что каждому физическому перемещению соответствует отдельный вызов обработчика. При необходимости приложение может запланировать или объединить ресурсоемкую отрисовку, сохраняя состояние привязанным к активному указателю.
Если интерфейс поддерживает несколько одновременных указателей, например жест двумя пальцами на холсте, храните состояние отдельно по идентификатору каждого указателя, а не исходите из того, что активен только один. Для более простых элементов управления намеренная поддержка только одного активного взаимодействия может упростить объяснение и тестирование. В обоих случаях определите, что произойдет, если второй указатель начнет действие, пока активен первый. Игнорирование второго указателя, отмена текущего действия или переход в режим нескольких указателей должны быть осознанным решением продукта, а не случайным побочным эффектом.
pointerup отмечает завершение активного действия указателя. В этот момент естественно переместить элемент в конечное положение, завершить штрих или решить, следует ли активировать элемент управления после нажатия. Перед фиксацией проверьте место назначения и сообщите результат. Если перетаскиваемый элемент нельзя поместить в выбранное место, верните его в понятную допустимую позицию и объясните ограничение вместо того, чтобы оставлять его в неопределенном состоянии. Действие, подобное щелчку, не должно активироваться только потому, что началось нажатие: пользователь мог отвести указатель, отменить действие или применить жест платформы.
Порядок событий указателя определяется платформой и может включать события совместимости для содержимого, рассчитанного на мышь. Не связывайте одно и то же действие приложения с несколькими семействами событий так, чтобы оно выполнялось дважды. Для каждого взаимодействия предусмотрите один понятный путь и проверьте его в браузерах и условиях ввода, которые поддерживает продукт. Если код приложения также обрабатывает активацию с клавиатуры, используйте обычное семантическое поведение элемента управления вместо дублирования действия, предназначенного только для указателя, в несвязанных обработчиках событий.
Последовательность не обязательно заканчивается событием pointerup. Страница должна учитывать pointercancel как полноценный способ завершения взаимодействия. Браузер может отменить действие указателя, если ему нужно обработать другое поведение или если взаимодействие больше не может продолжаться ожидаемым образом. Точные обстоятельства зависят от платформы и действия. Воспринимайте отмену как сигнал прекратить текущий жест, отбросить или безопасно завершить его временное состояние и вернуть интерфейс в работоспособное состояние. Это не означает, что пользователь сделал что-то неправильно.
Отмена особенно важна для сенсорного ввода, поскольку ответственность за жесты разделяют браузер и страница. Когда человек начинает перемещать палец по странице, браузер может интерпретировать движение как прокрутку или масштабирование, а не как перетаскивание в приложении. CSS-свойство touch-action позволяет приложению объявить, какие варианты прямого управления оно обрабатывает в определенной области. Выбирайте наиболее узкое поведение, необходимое элементу управления. Широкое отключение жестов браузера может затруднить работу со страницей и нарушить ожидаемое поведение браузера.
После pointerup или pointercancel сбросьте активное состояние взаимодействия и временное визуальное оформление. Если взаимодействие использует захват указателя, также обработайте уведомление о потере захвата. Очистку должно быть безопасно выполнять несколько раз: завершения могут совпасть с удалением компонента, сменой маршрута или отменой со стороны браузера. Идемпотентная очистка предотвращает повторную фиксацию результата и устаревшее состояние интерфейса. Например, перетаскивание элемента списка должно либо один раз завершиться в допустимом месте, либо вернуть элемент на прежнее место, но не делать и то и другое.
Удерживайте перетаскивание с помощью захвата указателя
Во время перетаскивания указатель может выйти за пределы элемента, на котором началось взаимодействие. Без явной стратегии цель событий может смениться на другой элемент, и исходный элемент управления перестанет получать события, необходимые для завершения действия. Захват указателя позволяет элементу продолжать получать события определенного активного указателя, даже когда тот перемещается в другую часть страницы. Код может запросить захват с помощью setPointerCapture(), указав идентификатор активного указателя, а затем при необходимости освободить его.
Захват полезен для взаимодействий, смысл которых сохраняется за пределами начальной области нажатия: перемещения ползунка, перетаскивания элемента, изменения размера панели или рисования на холсте. Он не фиксирует указатель и не удерживает его внутри захватившего элемента. Меняется цель событий, благодаря чему взаимодействие можно предсказуемо завершить и очистить. Привяжите визуальную обратную связь к текущему положению указателя и ясно показывайте результат действия.
Для сенсорного ввода и пера, которые браузер обрабатывает как прямое управление, платформа может неявно захватить указатель после его начала. Это помогает сохранять привязку непрерывного жеста к исходному элементу. Если приложение явно захватывает указатель, делать это следует только после начала активного указателя и нужно учитывать возможность окончания захвата. При завершении или отмене сбросьте связанное состояние и не предполагайте, что захват сохранится при любом переходе жизненного цикла.
Захват не заменяет продуманные границы взаимодействия. Захваченное действие указателя все равно может быть отменено, а пользователь должен иметь возможность остановить или обратить длительное действие. Если перетаскивание управляет чем-то существенным, предусмотрите наглядный предварительный просмотр, предсказуемый момент фиксации и способ восстановиться после случайного перемещения. Не превращайте небольшое неточное движение в необратимое действие. Если ту же задачу проще выполнить щелчком, командой с клавиатуры или через меню, предложите такой вариант.
Продумайте, что произойдет, если захвативший элемент будет удален или заменен во время отрисовки. При изменении состояния фреймворки могут создавать новые узлы DOM; новый узел автоматически не продолжает все взаимодействия со старым. По возможности сохраняйте стабильность элемента, управляющего взаимодействием, и выполняйте очистку при удалении компонента. Если во время перетаскивания пользователь сменил маршрут или закрыл диалог, не оставляйте скрытое взаимодействие активным в фоновом режиме.
Делайте понятными действия мышью, сенсорным вводом и пером
При работе мышью можно показывать обратную связь при наведении, но она должна быть дополнительной. Не скрывайте важные инструкции, подписи или элементы управления за состоянием, которое может вызвать только мышь. У человека одновременно могут быть подключены сенсорный экран и мышь; клавиатура также может использоваться на устройстве, которое обычно называют мобильным. Макет, который один раз спрашивает, каким устройством пользуется человек, не описывает все последующие взаимодействия.
При сенсорном вводе элементами управления должно быть легко воспользоваться, а соседние действия следует визуально разделять. Сенсорный ввод не сводится к менее точной мыши: область контакта шире, палец закрывает часть экрана, а браузер может зарезервировать жесты для прокрутки или масштабирования. Оставляйте между соседними действиями достаточно места для предотвращения случайного выбора, используйте подписи, объясняющие результат, и не делайте маленький значок единственной активной областью. Увеличенная область нажатия помогает уменьшить число ошибок при разных способах ввода, но не служит способом распознать устройство.
Перо может быть полезно для письма, рисования, аннотирования или выбора точных элементов. Если приложение использует свойства пера, предусмотрите подходящее базовое поведение для указателей, которые эти свойства не предоставляют. Например, приложением для заметок должно оставаться удобно пользоваться пальцем или мышью, даже если поддерживаемое перо позволяет рисовать с учетом силы нажатия. Сила нажатия, наклон или особая возможность пера не должны быть обязательны для обычной навигации или заполнения формы.
Не пытайтесь определять навыки или потребности человека в доступности по pointerType. Это свойство описывает общую категорию события в API, но не доказывает, что человек держит конкретный продукт, использует определенную руку, способен выполнить жест или предпочитает этот способ ввода. Пользователи могут полагаться на переключатели, голосовой ввод, альтернативные указатели или средства специальных возможностей браузера, которые не укладываются однозначно в обозначения «мышь», «сенсорный ввод» и «перо». Приложениям не следует сохранять характеристики указателя как признак личности; собирать стоит только те данные о взаимодействии, у которых есть ясная и раскрытая цель для продукта.
За многие элементы среды взаимодействия по-прежнему отвечает браузер, включая собственные жесты, управление фокусом и интеграцию со вспомогательными технологиями. Веб-странице не следует заменять эти механизмы пользовательской симуляцией событий или скрывать от сайта либо сервиса способ ввода. Создавайте интерфейс, который сохраняет реальный контроль пользователя: показывайте текущее состояние, соблюдайте поведение платформы и позволяйте человеку выбирать доступный способ продолжить работу.
Клавиатура как параллельный способ управления
Pointer Events сами по себе не обеспечивают доступ с клавиатуры. Визуально заметный маркер перетаскивания все равно может быть недоступен человеку, который пользуется клавиатурой. Для каждой важной для рабочего процесса задачи нужен способ перейти к ней и выполнить ее без перемещения указателя. Когда это соответствует задаче, используйте встроенные интерактивные элементы для кнопок, ссылок, полей форм и переключателей. Встроенные элементы уже участвуют в управлении фокусом и взаимодействии с клавиатуры, тогда как пользовательские визуальные элементы не получают это поведение автоматически.
Руководство WCAG по клавиатуре описывает параллельное требование: функциональность должна быть доступна через интерфейс клавиатуры без обязательного особого перемещения указателя. Pointer Events может поддерживать один путь взаимодействия, но не заменяет это требование к клавиатуре.
Для пользовательского виджета определите, как человек входит в него, перемещается между его частями, выполняет действие и выходит. Фокус должен оставаться видимым. Используйте ожидаемое для типа элемента поведение клавиатуры и предоставляйте его имя, роль и состояние подходящими семантическими средствами. Например, пользовательскому ползунку нужна не только ручка, следующая за pointermove, но и фокусируемый элемент управления, понятное отображение значения и возможность изменить его с клавиатуры. Для сортируемого списка предусмотрите с клавиатуры выбор элемента, его перемещение, подтверждение нового положения либо отмену с восстановлением исходного порядка.
Не связывайте логику приложения только с низкоуровневым событием указателя, если то же действие можно выразить семантической кнопкой или элементом формы. Активация встроенной кнопки с клавиатуры, с помощью вспомогательной технологии или указателя должна запускать одну и ту же команду. Если для сложных взаимодействий с холстом встроенной семантики недостаточно, дополните холст элементами управления или структурированной альтернативой, позволяющей выполнить ту же содержательную работу. Одного текстового описания недостаточно, если задача требует редактировать данные или выбирать значения.
Способы работы с клавиатуры и указателя не обязаны выглядеть одинаково. Перетаскивание может быть естественным жестом указателя, а для клавиатуры можно предоставить явные команды «переместить вверх» и «переместить вниз». Важно, чтобы обоими способами можно было достичь одного и того же значимого результата и увидеть изменения состояния. Сообщайте или показывайте подтверждение перемещения элемента, сохраняйте фокус на подходящем элементе и позволяйте пользователю отменить действие. Не вводите ограничения по времени, вынуждающие быстро завершить жест.
Проверяйте порядок фокуса вместе с порядком действий указателем. При открытии всплывающей панели фокус следует перемещать туда, где этого требует взаимодействие; при закрытии он должен возвращаться к понятному элементу. Выбор указателем не должен глобально убирать индикаторы фокуса. Пользователь может выбрать элемент сенсорным касанием, а затем продолжить работу с физической клавиатуры. Считайте такие переходы обычными и показывайте текущее состояние фокуса и выбора.
Проверяйте результаты в разных условиях ввода
Межустройственное тестирование наиболее полезно, когда одна и та же задача проверяется в небольшом, заранее определенном наборе условий. Включите сценарий для настольного компьютера с мышью и клавиатурой, сценарий преимущественно с сенсорным вводом на телефоне или планшете, а также перо, если приложение действительно его поддерживает. Добавьте работу только с клавиатуры на настольном компьютере и хотя бы один узкий размер окна. При разборе проблемы совместимости записывайте версии браузера и платформы, но не превращайте тестирование в перепись устройств пользователей.
Для каждой задачи задайте проверяемый результат: меню открывается и закрывается, карточку можно переместить в допустимое место, рисунок можно завершить, значение можно изменить или ошибку можно исправить. Затем проверьте весь жизненный цикл. Начните действие, переместите указатель за пределы исходной цели, завершите действие внутри и снаружи элемента управления, если это уместно, отмените его, прервите работу компонента и повторите попытку. Убедитесь, что интерфейс не застревает в нажатом, перемещаемом или модальном состоянии.
При сенсорном тестировании учитывайте жесты браузера. Прокрутите страницу с областью перетаскивания. Убедитесь, что в нужных местах сохраняется обычная прокрутка и что намеренное прямое управление случайно не блокирует все перемещения страницы. Проверяйте значение touch-action на самом узком подходящем элементе, а не отключайте жесты во всем приложении. Убедитесь, что масштабирование и навигация браузера остаются доступными, если только у продукта нет конкретного обоснованного требования к взаимодействию.
Проверяйте удобство целей при реалистичном размере экрана. Пользуйтесь интерфейсом одной рукой, если это вероятный сценарий, тестируйте элементы управления у краев экрана и ищите расположенные слишком близко элементы. Не ограничивайтесь нажатием в центре большого монитора точным курсором. Проверьте, остаются ли подписи и состояние понятными, когда палец или рука закрывает часть элемента управления. Если это важно для рабочего процесса, проверьте ориентацию экрана и прокрутку.
Затем повторите основную задачу без указателя. Переходите между элементами клавиатурой, активируйте элементы управления, меняйте значения, переставляйте содержимое и исправляйте ошибку. Убедитесь, что фокус остается видимым и не скрывается за диалогом или закрепленной областью. Если рабочий процесс поддерживает вспомогательные технологии, проверяйте их на тех платформах, поддержку которых обещает продукт. Проверка событий указателя не заменяет тестирования имен, ролей, объявлений состояния и порядка чтения.
Автоматизированные тесты помогают проверять сброс состояния и обработку событий, но не доказывают, что целью удобно пользоваться, подписи понятны или сценарий клавиатуры логичен. Дополняйте автоматические проверки практической оценкой на репрезентативных устройствах и версиях браузеров. Ведите краткую таблицу: задача, способ ввода, ожидаемый результат, фактический результат, браузер и платформа, дальнейшие действия. Ограничивайте снимки экрана и журналы взаимодействий необходимым для теста и не записывайте личное содержимое или избыточные данные об указателях.
Если дефект проявляется на одной платформе, сначала выделите видимое пользователю поведение. Проверьте, получила ли страница отмену, завершился ли захват указателя, переместился ли фокус и соответствует ли обработка жестов браузера задуманному интерфейсу. Сравнивайте поддерживаемую версию браузера с обновлением или другим типичным устройством только тогда, когда это помогает объяснить поведение. Не пытайтесь определять личность пользователя или создавать последовательности событий, чтобы добиться другого результата. Работа над совместимостью должна улучшать реальное взаимодействие для людей, использующих приложение.
Для каждого важного взаимодействия используйте исполнимую матрицу приемки:
Выполняйте эти случаи по Рекомендации W3C Pointer Events уровня 3 и применимым критериям WCAG 2.2. Возьмите две конкретные задачи: перетащите карточку для изменения порядка и нарисуйте штрих на холсте. Фиксируйте наблюдаемый результат, а не предполагаемое устройство.
| Случай | Подготовка и действие | Критерии прохождения | Фиксируемое свидетельство |
|---|---|---|---|
| Завершение перетаскивания | Захватите карточку, выйдите за пределы исходной цели и отпустите над допустимым местом. | Один цикл pointerdown/pointerup один раз меняет порядок; новый порядок и статус успеха видимы, следующий элемент работает. | Трасса событий, порядок и видимый статус. |
| Завершение рисования | Нажмите на холсте, нарисуйте штрих и отпустите внутри или сразу за пределами исходной области. | Штрих фиксируется один раз, остается видимым, а завершение доступно зрению и вспомогательной технологии. | Трасса указателя, отрисованный штрих и статус/объявление. |
| Отмена | Вызовите pointercancel (или явную команду Escape/отмены), затем проверьте очистку lostpointercapture; отдельно проверьте pointerup, за которым следует lostpointercapture. | Путь отмены выполняет один откат; подтвержденный pointerup остается подтвержденным один раз. Сам lostpointercapture не выполняет откат и не дублирует фиксацию; захват, стили и временный штрих очищаются. | Последовательность событий и проверка после отмены/фиксации. |
| Альтернатива и фокус | Переставьте карточку только клавиатурой и один раз отмените действие. Для рисования определите, зависит ли задача от свободного траектории; если нет, предоставьте эквивалентную структурированную/значимую альтернативу с клавиатуры. | Перестановка клавиатурой доступна и работоспособна, фокус видим, успех/отмена объявляются. Для рисования документируется продуктовая клавиатурная или структурированная альтернатива, когда она нужна; одного описания недостаточно для редактирования или выбора значений. | Клавиши, фокус, решение по задаче и текст состояния. |
| Восстановление и ошибка | Выберите недопустимое место или удалите представление-владелец, затем повторите попытку. | Временное состояние удалено; пользователь видит понятное сообщение об ошибке и восстановленный результат; повтор не дублирует действие. | Сообщение об ошибке, состояние, действие и второй результат. |
Случай считается проваленным, если отсутствует любой критерий или результат выводится только из pointerType, времени или метки устройства. Приемка проверяет наблюдаемое поведение, а не определяет человека или устройство, создавшее ввод.
Практический контрольный список
Перед выпуском убедитесь, что для каждого пользовательского взаимодействия указателем определены начало, перемещение, успешное завершение, отмена и очистка. Проверьте, что временное состояние удаляется после прерывания и что действие не может быть зафиксировано дважды. Используйте захват указателя только тогда, когда взаимодействие должно продолжаться за пределами исходного элемента, и обрабатывайте окончание захвата.
Убедитесь, что наведение мыши не является единственным способом обнаружить или использовать функцию. У сенсорных целей практичные размер и расстояние друг от друга, прокрутка и масштабирование браузера остаются доступны, а улучшения только для пера не мешают другим пользователям выполнить задачу. Выбирайте touch-action осознанно и ограничивайте любое ограничение взаимодействием, которому оно необходимо.
Наконец, выполните ту же важную задачу только с клавиатуры. Проверьте видимость фокуса, семантику, обратную связь о состоянии и отмену. Протестируйте представительный набор браузеров, размеров окна и способов ввода; зафиксируйте то, что действительно проверено, и собирайте свидетельства тестирования в объеме, соразмерном его цели. Pointer Events служит общей основой, но доступность взаимодействия зависит от всего опыта вокруг нее: понятных элементов управления, выбора пользователя, возможности восстановиться и совместимости с поведением платформы.
Открытые источники
- Рекомендация W3C Pointer Events уровня 3
- MDN Pointer Events
- WCAG: Клавиатура
- WCAG 2.5.2: Отмена указателя (прямой источник для строк отмены)
- WCAG 2.5.8: Минимальный размер цели (рекомендация по размеру; приложение может требовать большего)
- WCAG 2.4.7: Видимый фокус и 2.4.11: Фокус не перекрыт (минимум) (критерии фокуса; проверки одной фиксации и повтора определяются приложением)
Похожие статьи
Переведите BotBrowser из исследований в продакшн
Используйте эти руководства, чтобы понять модель, а затем перейти к кроссплатформенной валидации, изолированным контекстам и масштабируемому браузерному развертыванию.