Навигация без мышки

от автора

Наверное все при взгляде на этот экран мысленно переносят обе руки на клавиатуру. Да, тут можно было навигироваться без мышки и это было быстро и хорошо! Многие до сих пор используют подобные менеджеры (Total commander, Far etc).

С другой стороны, почти на всех современных сайтах, порталах и решениях построенных для веба пользователь вынужден постоянно отрывать руки от клавиатуры, целиться мышкой в кнопку/иконку/поле, а затем опять возвращать руки на клавиатуру для ввода текста.

Как же достичь удобства навигации без мышки в вебе?

Большая часть продуктов, которые разрабатывает и внедряет наша компания выходит на конечного пользователя. Операторы кол-центров, инженеры, менеджеры – все они работают с пользовательским интерфейсом «для внутреннего использования» – B2B интерфейсами. Возможность работы с системой с клавиатуры без использования мыши – важное требование в B2B интерфейсах. Почему?

  • В первую очередь – скорость работы. Пользователю не нужно изменять положение рук и переключаться на мышку, напротив у него есть мгновенный доступ к функциям.
  • Пользователю сложнее сделать ошибку (нужно целиться в кнопку, а не в пиксель).
  • Поддержка людей с ограниченными возможностями расширенными потребностями.
  • Снижение нагрузки на глаза (многие функции можно выполнять вообще не смотря на монитор).

Такая навигация может выглядеть не «секси» и требовать больше времени на обучение, но бонусы от использования значительно превышают эти минусы.

Итак, задача

Есть большое количество web-based пользовательских интерфейсов. Необходимо:

  • с минимумом усилий позволить использовать весь функционал наших решений без мыши
  • иметь возможность быстро адаптировать любые новые страницы для использования без мыши
  • иметь возможность тонкой настройки навигации по АРМам для увеличения эффективности работы всех пользователей
  • все это с минимальным воздействием на существующий код

Анализируем

Существует четыре основных подхода к навигации клавиатурой, рассмотрим их:

  • табуляция (tab)
  • хоткеи (hotkeys)
  • пространственная навигация (spatial)
  • каретка (caret)
Табуляция

Табуляция — переход между элементами интерфейса с помощью клавиши tab (shift+tab).

  • + поддержка по умолчанию во всех популярных браузерах
  • − всего два направления (+shift)
  • − ограниченные возможности конфигурации (ring)…
Хоткеи

Хоткеи — сочетание клавиш, которое вызывает определённую функцию. Это позволяет упростить доступ к основным функциям системы. Всё больше сайтов начинают использовать хоткеи на свои страницах для доступа к самым востребованным функциям, среди них: Habrahabr, яндекс, гугл почта и другие. Но что делать, если функций много и на каждой странице разные? Просто невозможно будет запомнить все хоткеи, а значит, использование не будет эффективным. Так же есть проблема контекста: когда на странице несколько таблиц и несколько кнопок save например.

  • + мгновенный вызов любой функции
  • − требует обучения (запоминания сочетаний клавиш)
  • − при большом количестве функций сложно запомнить сочетания (особенно если несколько страниц как у нас)

Пример реализации: расширения для Firefox (ссылка) использует подход с hotkeys, очень распространены в десктоп приложениях (пример аутлук).

  • + не нужно менять существующий код
  • − только браузер Firefox
  • − несколько кнопок save
  • − никакой семантики, такие хоткеи сложно запомнить
  • − на разных страницах одни и те же действия могут иметь разные хоткеи
Пространственная навигация

Когда элементы на веб страницах стали позиционировать с помощью css, навигация табом перестала справляться со своей задачей: курсор перескакивал по элементам дизайна в порядке их объявления в html документе, а не в том каком их видит пользователь. Тогда некоторые браузеры (Firefox, Opera) реализовали пространственную навигацию. Они позволяли пользователям использовать сочетания shift+стрелки для перемещения между элементами дизайна, причём следующий элемент определялся исходя из его фактического расположения на экране.

  • + позволяет навигироваться по незнакомому интерфейсу
  • + поддержка OOB в некоторых браузерах
  • − поддержка не во всех браузерах
  • − там где поддержка есть, она включается опционально
  • − нет стандарта сочетаний клавиш для переходов
Перемещение каретки

Особенность этого подхода в том, что курсор пользователя перемещается не только по элементам форм и ссылкам, а по всему содержимому страницы (как в ворде). Перемещаться можно, как и в пространственном подходе, в четырёх направлениях.

  • + позволяет выделять, копировать фрагменты текста
  • − сфокусирован на контенте, а не элементах управления
  • − медленнее, чем пространственная навигация

Вышеприведенные решения as is нам не подходят из-за отсутствия поддержки во всех браузерах, в них отсутствует возможность тонкой настройки для конкретных страниц, а также хотелось бы чтобы и хоткеи и пространственная навигация настраивались единообразно в одном месте.

Представляем Mouseless

Ключевыми особенностями Mouseless являются:

  • простая конфигурация для всех страниц приложения используя CSS селекторы
  • работа во всех браузерах
  • возможность тонкой настройки
  • не конфликтует с существующими решениями
  • хоткеи и пространственная навигация в одном флаконе
Принцип работы Mouseless

Страница делится на блоки с помощью привычных CSS селекторов. Блоки могут иметь дочерние блоки. Внутри каждого блока определяется свой набор хоткеев (JSON объект). Хоткеи могут наследоваться внутренними блоками, т.е. у хоткеев появляется скоуп, которым можно управлять (например, хоткей для сохранения один и тот же в разных блоках, но работает по-разному в зависимости от текущего блока).


На рисунке показано разделение на блоки и под блоки.

Конфигурация каждого блока представляет из себя json объект, json объекты для всех блоков образуют конфигурацию страницы.

Пространственная навигация в данном случае является частным случаем хоткеев. Сводим к минимуму кол-во обязательных параметров конфигурации, базовая поддержка должна быть доступна с минимумом действий. Простейшая конфигурация:

new MouselessBlock({  //объявление блока 	selector: "#blockId", // селектор задаёт границы блока 	childSelector: “a”, // селектор определяет элементы на которые будет перемещаться фокус 	keys: [ // массив хранит все хоткеи используемые в данном блоке 		new MouselessAction({key: ncKey.KEY_LEFT, action: ncKey.gotoPrevElem }), //по нажатию на клавишу влево выполнить переход на предыдущий элемент 		new MouselessAction({key: ncKey.KEY_RIGHT, action: ncKey.gotoNextElem }) 	] }); 

Внутри блока #blockId можно перемещать фокус между ссылками клавишами влево и вправо. gotoPrevElem/gotoNextElem служебные функции, можно так же использовать свои кастомные функции.

На реальных кейсах расширяем базовую библиотеку:

  • кольца. Чтобы навигироваться по списку вновь и вновь по кругу, нужно в блок добавить параметр ring: true
  • элементы блока получающие фокус по умолчанию возможность указать элемент, который первым получает фокус при попадании в блок defaultChildIndex:2
  • поддержка пользовательских функций можно установить свою собственную функцию, которая будет вызвана по нажатию клавиш. new MouselessAction({key: ncKey.KEY_LEFT, action: customFunction })
  • работа с диалоговыми окнами (попапами) модальные окна работают в отдельном контексте, их конфигурация осуществляется независимо от основной
    ncKey.addBaseConf(parentSelector, blocks); //добавление блоков в основную конфигурацию ncKey.addCustomConf(parentSelector, blocks); //добавление блоков в конфигурацию динамически подключаемых модальных блоков //parentSelector - селектор родительского блока, если "" - добавление в корень конфигурации. //blocks - массив блоков для добавления 
  • сохранение/восстановление фокуса применяется в основном совместно с модальными окнами для приведения фокуса в состояние до открытия окна
    var curFocus = ncKey.saveFocus();  … ncKey.restoreFocus(curFocus); 
  • наследование ncKeyAction’ов, поддержка глобальных хоткеев например на странице есть несколько таблиц, у каждой кнопка save. Хотим чтобы в любой ячейке таблицы можно было выполнить сохранение по хоткею (частный случай глобальные хоткеи). Т.е. ncKeyAction назначенные в родительском блоке будут работать во всех дочерних:
    ncKey.addCustomConf("", [new MouselessBlock({//блок описывающий попап         selector:"#popup-window",         childSelector: ncKey.FOCUSABLE_SELECTOR,         keys: [new MouselessAction({key: ncKey.KEY_ESCAPE,  action: closePopup}),                 new MouselessAction({key: ncKey.KEY_S,  action: saveAndClosePopup})         ],         childBlocks: [new MouselessBlock({ //дочерний блок с контентом                 selector:"#popup-window .body",                 childSelector: ncKey.FOCUSABLE_SELECTOR,                 ring: false,                 keys: [...]             }),             new MouselessBlock({ //дочерний блок с кнопками                 selector:"#popup-window .btns",                 childSelector: ncKey.FOCUSABLE_SELECTOR,                 ring: false,                 keys: [...]            }) 		] 	}) ]); 

    Закрытие попапа с сохранением и без будет работать во всех блоках.

Конфигурация блока на примере NavigationTree (раскрывающее дерево):

new MouselessBlock({  selector: "#navigationTree", childSelector: "li > a:visible", ring: true, keys: [ new MouselessAction({key: ncKey.KEY_LEFT, action: ncKey.gotoPrevBlock, ctrl: true}),            new MouselessAction({key: ncKey.KEY_RIGHT, action: ncKey.gotoNextBlock, ctrl: true}),            new MouselessAction({key: ncKey.KEY_UP, action: ncKey.gotoPrevElem, ctrl: false}),            new MouselessAction({key: ncKey.KEY_DOWN, action: ncKey.gotoNextElem, ctrl: false}),             new MouselessAction({key: ncKey.KEY_RIGHT, action: openNavTreeNode, ctrl: false}),             new MouselessAction({key: ncKey.KEY_LEFT, action: closeNavTreeNode, ctrl: false})  ]}); 

Теперь можно ходить по дереву стрелками вверх-вниз, открывать закрывать ветки влево-вправо. Функции openNavTreeNode/closeNavTreeNode были написаны до внедрения Mouseless (были опубликованы как api к дереву). Таким образом даже в этом случае не пришлось писать новый код, обходимся простой конфигурацией.
CSS легко заменяется под любую тему, достаточно описать правила для подсветки активируемых элементов и активного. Можно добавить свои более сложные для конкретных блоков или элементов.

Итого

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

Дополнительным бонусом стало то, что мы покрыли часть рекомендаций W3C “Web Content Accessibility Guidelines” ( www.w3.org/TR/WCAG20 ).

Работа в этом направлении не закончена, будем продолжать, ждём реакцию сообщества.

ссылка на оригинал статьи http://habrahabr.ru/post/273071/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *