Снова вместе в первый раз
Введение
Почти тридцать лет настольные компьютерные возможности были сосредоточены вокруг клавиатуры и мыши или трекпада в качестве основных устройств ввода данных. Однако за последнее десятилетие смартфоны и планшеты принесли новую парадигму взаимодействия: касание. С появлением сенсорных машин Windows 8, а теперь и с выпуском потрясающего сенсорного Chromebook Pixel, касание становится частью ожидаемого опыта работы с настольными компьютерами. Одной из самых больших проблем является создание опыта, который работает не только на сенсорных устройствах и устройствах с мышью, но и на этих устройствах, где пользователь будет использовать оба метода ввода — иногда одновременно!
Эта статья поможет вам понять, как сенсорные возможности встроены в браузер, как можно интегрировать этот новый механизм интерфейса в ваши существующие приложения и как сенсорное управление может прекрасно сочетаться с вводом с помощью мыши.
Состояние сенсорного взаимодействия на веб-платформе
iPhone был первой популярной платформой, которая имела выделенные сенсорные API, встроенные в веб-браузер. Несколько других поставщиков браузеров создали похожие интерфейсы API, совместимые с реализацией iOS, которая теперь описывается спецификацией «Touch Events version 1» . Сенсорные события поддерживаются Chrome и Firefox на настольных компьютерах, Safari на iOS и Chrome, а также браузером Android на Android, а также другими мобильными браузерами, такими как браузер Blackberry.
Мой коллега Борис Смус написал отличный учебник HTML5Rocks по событиям Touch , который все еще является хорошим способом начать, если вы раньше не рассматривали события Touch. На самом деле, если вы раньше не работали с событиями Touch, прочитайте эту статью сейчас, прежде чем продолжить. Продолжайте, я подожду.
Все готово? Теперь, когда у вас есть базовые знания о сенсорных событиях, проблема с написанием сенсорных взаимодействий заключается в том, что сенсорные взаимодействия могут существенно отличаться от событий мыши (и эмулирующих мышь трекпада и трекбола) — и хотя сенсорные интерфейсы обычно пытаются эмулировать мышь, эта эмуляция не идеальна и не полна; вам действительно нужно проработать оба стиля взаимодействия и, возможно, поддерживать каждый интерфейс по отдельности.
Самое главное: пользователь может иметь сенсорное управление и мышь
Многие разработчики создали сайты, которые статически определяют, поддерживает ли среда события касания, а затем делают предположение, что им нужно поддерживать только события касания (а не мыши). Теперь это ошибочное предположение — вместо этого, просто наличие событий касания не означает, что пользователь в первую очередь использует это устройство сенсорного ввода. Такие устройства, как Chromebook Pixel и некоторые ноутбуки с Windows 8, теперь поддерживают ОБА метода ввода мышью и касанием, и в ближайшем будущем их будет больше. На этих устройствах вполне естественно, что пользователи используют и мышь, и сенсорный экран для взаимодействия с приложениями, поэтому «поддерживает касание» — это не то же самое, что «не нуждается в поддержке мыши». Вы не можете думать о проблеме как «мне нужно написать два разных стиля взаимодействия и переключаться между ними», вам нужно продумать, как оба взаимодействия будут работать вместе, а также независимо. На моем Chromebook Pixel я часто использую трекпад, но я также тянусь и касаюсь экрана — в одном и том же приложении или на одной и той же странице я делаю то, что кажется наиболее естественным в данный момент. С другой стороны, некоторые пользователи ноутбуков с сенсорным экраном редко пользуются сенсорным экраном, если вообще пользуются, поэтому наличие сенсорного ввода не должно отключать или затруднять управление мышью.
К сожалению, может быть сложно узнать, поддерживает ли браузерная среда пользователя сенсорный ввод или нет; в идеале браузер на настольном компьютере всегда должен показывать поддержку сенсорных событий, чтобы сенсорный дисплей можно было подключить в любое время (например, если сенсорный экран, подключенный через KVM , становится доступным). По всем этим причинам ваши приложения не должны пытаться переключаться между сенсорным экраном и мышью — просто поддерживайте оба!
Совместная поддержка мыши и сенсорного управления
#1 - Щелчки и нажатия - "естественный" порядок вещей
Первая проблема заключается в том, что сенсорные интерфейсы обычно пытаются эмулировать щелчки мыши — очевидно, поскольку сенсорные интерфейсы должны работать в приложениях, которые ранее взаимодействовали только с событиями мыши! Вы можете использовать это как ярлык — поскольку события «щелчка» будут продолжать срабатывать, независимо от того, щелкнул ли пользователь мышью или коснулся экрана пальцем. Однако с этим ярлыком есть пара проблем.
Во-первых, нужно быть осторожным при проектировании более сложных сенсорных взаимодействий: когда пользователь использует мышь, она будет реагировать через событие щелчка, но когда пользователь касается экрана, будут происходить как события касания, так и щелчка. Для одного щелчка порядок событий следующий:
- сенсорный старт
- touchmove
- тачэнд
- наведение мыши
- перемещение мыши
- mousedown
- мышь вверх
- нажмите
Это, конечно, означает, что если вы обрабатываете события касания, такие как touchstart, вам нужно убедиться, что вы не обрабатываете также соответствующее событие mousedown и/или click. Если вы можете отменить события касания (вызвать preventDefault() внутри обработчика событий), то никакие события мыши не будут генерироваться для касания. Одно из самых важных правил обработчиков касания:
Однако это также предотвращает другое поведение браузера по умолчанию (например, прокрутку) - хотя обычно вы обрабатываете событие касания полностью в своем обработчике, и вы ХОТИТЕ отключить действия по умолчанию. В общем, вы либо захотите обрабатывать и отменять все события касания, либо избегать обработчика для этого события.
Во-вторых, когда пользователь нажимает на элемент веб-страницы на мобильном устройстве, страницы, не предназначенные для мобильного взаимодействия, имеют задержку не менее 300 миллисекунд между событием touchstart и обработкой событий мыши (mousedown). Это можно сделать с помощью Chrome, вы можете включить «Эмулировать события касания» в Chrome Developer Tools, чтобы помочь вам протестировать сенсорные интерфейсы на несенсорной системе!
Эта задержка нужна для того, чтобы дать браузеру время определить, выполняет ли пользователь другой жест — в частности, масштабирование двойным нажатием. Очевидно, что это может быть проблематично в случаях, когда вы хотите иметь мгновенный ответ на касание пальцем. Ведется работа по ограничению сценариев, в которых эта задержка происходит автоматически.
Первый и самый простой способ избежать этой задержки — «сообщить» мобильному браузеру, что масштабирование вашей страницы не потребуется. Это можно сделать с помощью фиксированной области просмотра, например, вставив на страницу:
<meta name="viewport" content="width=device-width,user-scalable=no">
Конечно, это не всегда уместно — это отключает масштабирование пальцами, которое может потребоваться по соображениям доступности, поэтому используйте его умеренно, если вообще используете (если вы отключаете масштабирование пользователем, возможно, вам захочется предоставить какой-то другой способ повысить читаемость текста в вашем приложении). Кроме того, для Chrome на устройствах класса настольных компьютеров, которые поддерживают сенсорный ввод, и других браузеров на мобильных платформах, когда на странице есть области просмотра, которые не масштабируются, эта задержка не применяется.
#2: События Mousemove не запускаются при касании
На этом этапе важно отметить, что эмуляция событий мыши в сенсорном интерфейсе обычно не распространяется на эмуляцию событий mousemove, поэтому если вы создадите красивый элемент управления, управляемый мышью, который использует события mousemove, он, скорее всего, не будет работать с сенсорным устройством, если вы специально не добавите также обработчики touchmove.
Браузеры обычно автоматически реализуют соответствующее взаимодействие для сенсорных взаимодействий в элементах управления HTML — так, например, элементы управления HTML5 Range будут работать только при использовании сенсорных взаимодействий. Однако, если вы реализовали свои собственные элементы управления, они, скорее всего, не будут работать при взаимодействиях типа «щелчок и перетаскивание»; на самом деле, некоторые часто используемые библиотеки (например, jQueryUI) пока изначально не поддерживают сенсорные взаимодействия таким образом (хотя для jQueryUI есть несколько исправлений этой проблемы с помощью monkey-patch). Это была одна из первых проблем, с которыми я столкнулся при обновлении своего приложения Web Audio Playground для работы с сенсорными экранами — ползунки были основаны на jQueryUI, поэтому они не работали при взаимодействиях типа «щелчок и перетаскивание». Я перешел на элементы управления HTML5 Range, и они заработали. Конечно, я мог бы просто добавить обработчики touchmove для обновления ползунков, но с этим есть одна проблема…
#3: Touchmove и MouseMove — это не одно и то же
Ловушка, в которую я попадал, когда обработчики touchmove и mousemove вызывали одни и те же codepaths. Поведение этих событий очень похоже, но немного отличается — в частности, события касания всегда нацелены на элемент, с которого НАЧАЛОСЬ касание, в то время как события мыши нацелены на элемент, находящийся в данный момент под курсором мыши. Вот почему у нас есть события mouseover и mouseout, но нет соответствующих событий touchover и touchout — только touchend.
Наиболее распространенный способ, которым это может вас укусить, — это если вы случайно удалите (или переместите) элемент, к которому пользователь начал прикасаться. Например, представьте карусель изображений с обработчиком касания по всей карусели для поддержки настраиваемого поведения прокрутки. По мере изменения доступных изображений вы удаляете некоторые элементы <img>
и добавляете другие. Если пользователь случайно начнет прикасаться к одному из этих изображений, а затем вы удалите его, ваш обработчик (который находится на предке элемента img) просто перестанет получать события касания (потому что они отправляются цели, которая больше не находится в дереве) — это будет выглядеть так, как будто пользователь держит палец в одном месте, хотя он мог переместить его и в конечном итоге убрать.
Конечно, вы можете избежать этой проблемы, избегая удаления элементов, которые имеют (или имеют предков, которые имеют) обработчики касания, пока касание активно. В качестве альтернативы, лучшим руководством будет вместо регистрации статических обработчиков touchend/touchmove дождаться события touchstart, а затем добавить обработчики touchmove/touchend/touchcancel к цели события touchstart (и удалить их при завершении/отмене). Таким образом, вы продолжите получать события для касания, даже если целевой элемент перемещен/удален. Вы можете немного поиграть с этим здесь - коснитесь красного поля и, удерживая клавишу Escape, удалите его из DOM.
#4: Коснитесь и :наведите курсор
Метафора указателя мыши разделила положение курсора от активного выбора, и это позволило разработчикам использовать состояния наведения, чтобы скрывать и показывать информацию, которая может быть важна для пользователей. Однако большинство сенсорных интерфейсов сейчас не распознают «наведение» пальца на цель, поэтому предоставление семантически важной информации (например, предоставление всплывающего окна «что это за элемент управления?») на основе наведения является табу, если только вы также не предоставите удобный для касания способ доступа к этой информации. Вам нужно быть осторожным с тем, как вы используете наведение для передачи информации пользователям.
Однако довольно интересно, что псевдокласс CSS :hover МОЖЕТ быть вызван сенсорными интерфейсами в некоторых случаях — нажатие на элемент делает его :active, пока палец нажат, и он также приобретает состояние :hover. (В Internet Explorer :hover действует только пока палец пользователя нажат — другие браузеры сохраняют :hover действующим до следующего нажатия или перемещения мыши.) Это хороший подход к работе всплывающих меню в сенсорных интерфейсах — побочным эффектом активации элемента является то, что также применяется состояние :hover. Например:
<style>
img ~ .content {
display:none;
}
img:hover ~ .content {
display:block;
}
</style>
<img src="/awesome.png">
<div class="content">This is an awesome picture of me</div>
После нажатия на другой элемент элемент больше не активен, а состояние наведения исчезает, как если бы пользователь использовал указатель мыши и убрал его с элемента. Вы можете захотеть обернуть содержимое в элемент <a>
, чтобы сделать его также табуляцией — таким образом пользователь сможет переключать дополнительную информацию при наведении мыши или щелчке, касании или нажатии клавиши, без необходимости в JavaScript. Я был приятно удивлен, когда начал работать над тем, чтобы моя Web Audio Playground хорошо работала с сенсорными интерфейсами, что мои всплывающие меню уже хорошо работали на сенсорном экране, потому что я использовал такую структуру!
Вышеуказанный метод хорошо работает для интерфейсов на основе указателя мыши, а также для сенсорных интерфейсов. Это отличается от использования атрибутов "title" при наведении, которые НЕ будут отображаться при активации элемента:
<img src="/awesome.png" title="this doesn't show up in touch">
#5: Точность касания против мыши
Хотя мыши имеют концептуальную диссоциацию от реальности, оказывается, что они чрезвычайно точны, поскольку базовая операционная система обычно отслеживает точную точность пикселей для курсора. С другой стороны, разработчики мобильных устройств узнали, что касания пальцем сенсорного экрана не такие точные, в основном из-за размера площади поверхности пальца при контакте с экраном (и отчасти потому, что ваши пальцы загораживают экран).
Многие люди и компании провели обширные исследования пользователей о том, как разрабатывать приложения и сайты, которые поддерживают взаимодействие с помощью пальцев, и на эту тему написано много книг. Основной совет — увеличить размер сенсорных целей, увеличив отступы, и уменьшить вероятность неправильных нажатий, увеличив поля между элементами. (Поля не включены в обработку обнаружения касаний и щелчков, а отступы включены.) Одним из основных исправлений, которые мне пришлось сделать в Web Audio Playground, было увеличение размеров точек соединения, чтобы их было легче точно касаться.
Многие поставщики браузеров, работающие с сенсорными интерфейсами, также внедрили в браузер логику, помогающую выбирать нужный элемент при касании экрана пользователем и снижающую вероятность неправильных щелчков — хотя обычно это корректирует только события щелчков, а не перемещения (хотя Internet Explorer, по-видимому, также изменяет события mousedown/mousemove/mouseup).
#6: Держите обработчики касаний под контролем, иначе они испортят вашу прокрутку
Также важно ограничивать обработчики касаний только теми элементами, где они вам нужны; элементы касания могут иметь очень высокую пропускную способность, поэтому важно избегать обработчиков касаний на прокручиваемых элементах (так как ваша обработка может помешать оптимизации браузера для быстрой прокрутки касанием без задержек — современные браузеры пытаются прокручивать в потоке графического процессора, но это невозможно, если им сначала приходится проверять с помощью javascript, будет ли каждое событие касания обработано приложением). Вы можете ознакомиться с примером такого поведения.
Чтобы избежать этой проблемы, следует придерживаться одного совета: если вы обрабатываете события касания только в небольшой части пользовательского интерфейса, то прикрепляйте обработчики касаний только там (а не, например, в <body>
страницы). Короче говоря, следует максимально ограничить область действия обработчиков касаний.
#7: Мультитач
Последняя интересная проблема заключается в том, что хотя мы и называли это пользовательским интерфейсом "Touch", практически повсеместно поддержка фактически относится к Multi-touch, то есть API обеспечивают более одного сенсорного ввода одновременно. Когда вы начнете поддерживать сенсор в своих приложениях, вам следует подумать о том, как множественные касания могут повлиять на ваше приложение.
Если вы создавали приложения, в основном управляемые мышью, то вы привыкли создавать максимум с одной точкой курсора — системы обычно не поддерживают несколько курсоров мыши. Для многих приложений вы просто будете сопоставлять события касания с одним интерфейсом курсора, но большая часть оборудования, которое мы видели для сенсорного ввода на рабочем столе, может обрабатывать как минимум 2 одновременных ввода, а большинство нового оборудования, похоже, поддерживает как минимум 5 одновременных вводов. Для разработки экранной клавиатуры пианино , конечно, вам захочется иметь возможность поддерживать несколько одновременных сенсорных вводов.
В настоящее время реализованные W3C Touch API не имеют API для определения того, сколько точек касания поддерживает оборудование, поэтому вам придется использовать свою лучшую оценку того, сколько точек касания захотят ваши пользователи, или, конечно, обращать внимание на то, сколько точек касания вы видите на практике, и адаптироваться. Например, в приложении для фортепиано, если вы никогда не видите больше двух точек касания, вы можете захотеть добавить пользовательский интерфейс «аккордов». API PointerEvents имеет API для определения возможностей устройства.
Подкрашивание
Надеюсь, эта статья дала вам некоторые рекомендации по общим проблемам при реализации сенсорного взаимодействия вместе с мышью. Конечно, важнее всего то, что вам нужно тестировать свое приложение на мобильных устройствах, планшетах и комбинированных настольных компьютерах с мышью и сенсорным экраном. Если у вас нет оборудования сенсорного управления и мыши, используйте функцию Chrome " Эмулировать события касания ", чтобы протестировать различные сценарии.
Следуя этим рекомендациям, не только возможно, но и относительно легко создавать увлекательные интерактивные приложения, которые хорошо работают с сенсорным вводом, вводом с помощью мыши и даже с обоими стилями взаимодействия одновременно.