От автора: Если говорить о пользовательском опыте взаимодействия, то данная концепция является достаточно давней, и я какое-то время о ней не слышал, но она все равно остается актуальной в случае с многоуровневыми выпадающими меню. Такой мелкий указатель, как курсор мыши, иногда приходится перемещать в довольно ограниченном и узком пространстве, чтобы добраться до нужного пункта в выпадающем меню. Очень легко «сбиться с пути» (когда курсор мыши выходит за пределы активной области), и вы тут же будете наказаны за это, т.к. выпадающее меню закроется. Пожалуй, мы можем улучшить этот процесс.
Вы можете добраться до нужного вам пункта меню, но придется перемещать курсор мыши по довольно узким областям меню.
Многие выпадающие меню созданы таким образом, что если курсор мыши не наведен на нужную область (состояние :hover) или происходят события mouseleave или mouseout, то подменю с нужным нам пунктом может сразу закрыться.
Стандартный CSS подход
Выпадающие меню обычно создаются с расчетом на то, что подменю будет появляться при наведении (CSS состояние :hover) на родительский элемент. Или когда происходит срабатывание событий mouseenter / mouseover в JavaScript и смена состояния. Таким образом весь трюк состоит в попытке сделать так, чтобы эти условия нельзя было слишком легко выполнить. Т.е. нужно расширить активные области меню.
Основная причина, по которой я стал размышлять об этом, заключается в наличии слишком узких областей подменю в главном выпадающем меню на сайте CodePen. Чтобы расширить активные области в узких местах, я добавил пару псевдо-элементов в подменю. Если курсор мыши попадает на псевдо-элементы, то ничего не происходит, как будто курсор мыши находится в рамках подменю, как и должно быть.
Красным цветом выделены места, где расположены псевдо-элементы.
Это очень простая техника, требующая только использования CSS, и это мне нравится. Небольшая опасность заключается в том, что вы можете захватить порядочное количество места, отведенного под соседние пункты меню. А это означает, что пользователь не сможет при наведении кликнуть по нужному пункту меню. Я представляю огромное количество случаев, когда нужно всего лишь немного сместить курсор мыши в сторону, и все бы заработало, но это определенно балансирование между крайностями (слишком много, слишком мало).
История уходит корнями в далекий 2005 год к классическому демо-примеру Позиционирование — это Все:
А также, возможно, к демо-примеру Тьерри Кобленц (Thierry Koblentz).
Расширение CSS границ
Джон Гарднер (John Gardner) разработал подход, в котором все меню имеют дополнительное свободное пространство вокруг себя, которое позволит совершать безболезненный выход за рамки самого меню:
Намерение навести курсор мыши
Вы когда-нибудь слышали о «намерении навести курсор мыши» («hover intent»)? Это такая концепция, заключающаяся в том, что вы не сразу выдаете результат в ответ на срабатывание событий, связанных с перемещением курсора мыши. Вы выжидаете долю секунды, чтобы таким образом убедиться в том, что пользователь действительно хочет получить реакцию на свои действия. Это как намеренная задержка. Она используется в ситуациях, когда пользовательский интерфейс может работать слишком нестабильно при ее отсутствии.
В качестве противоположной стороны мы можем выделить «намерение отвести курсор мыши». Т.е., например, мы сразу реагируем на событие при наведении, но немного задерживаем реакцию, когда происходит отведение курсора мыши. В CSS можно прописать следующее:
1 2 3 4 5 6 7 8 |
.submenu { visibility: hidden; transition: 0.2s 1s; /* задержка в 1 секунду при отведении курсора мыши */ } .parent:hover .submenu { visibility: visible; transition-delay: 0s; /* незамедлительная реакция при наведении */ } |
Обратите внимание на то, что мы используем свойство visibility, которое можно использовать для переходов, в отличии от свойства display (что достаточно странно).
JavaScript также способен реализовать концепцию «намерения отвести курсор мыши». Здесь вы можете подойти к этому с точки зрения «функции с задержкой» (debounce), когда вы будете вызывать функции, выполняющие закрытие, не сразу, а только спустя какое-то время. Это можно реализовать, используя функцию setTimeout, которую вы будете отменять, если курсор мыши вернется обратно. Это слишком упрощенный вариант, но все же:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
var timer; $(".parent").on("mouseover", function() { clearTimeout(timer); openSubmenu(); }).on("mouseleave", function() { timer = setTimeout( closeSubmenu , 1000); }); function openSubmenu() { $(".submenu").addClass("open"); } function closeSubmenu() { $(".submenu").removeClass("open"); } |
Ни в одном из этих демо-примеров не показано решение проблемы путем увеличения размера. В данных примерах пользователю «прощается» быстрое отклонение от намеченного пути.
Избегайте узких областей
Не существует такого правила, что подменю должны раскрываться в сторону от выпадающего меню. Если подменю будут раскрываться сразу под нужным пунктом меню, то активная область останется широкой. Вот пример от Тимоти М. ЛеБланк (Timothy M. LeBlanc):
Новое решение с треугольником на JavaScript
Недавно Бен Кеймс (Ben Kames) написал замечательный пост на данную тему. Он проверял, насколько остроумно были сделаны выпадающие меню на сайте Amazon.com по сравнению с другими выпадающими меню, для которых применялись техники с временной задержкой для улучшения юзабилити. Оказалось, что вся магия кроется в математике! Если курсор мыши перемещается под допустимым углом по направлению к только что открывшемуся подменю, то это не будет вызывать реакции со стороны других пунктов меню. Визуально это выглядит вот так:
Бен создал из этого jQuery плагин. Вы также можете посмотреть демо-пример.
Он также безусловно прав в этом: «Я уверен, что данная проблема была решена уже много лет назад, потом забыта, потом вновь обнаружена, затем решена, а потом снова забыта и т.д.»
И это печальная правда, касающаяся многих аспектов в нашем ремесле. Джон Нил (Jon Neal) предпринял попытку избавиться от jQuery зависимости и улучшить математические вычисления, используя «барицентрические координаты» («barycentric coordinates»):
Другие мысли по теме
Думаю, что один мудрый человек однажды сказал: «Иногда у посетителей вашего сайта будет мышка, а иногда – нет».
Итак, будем надеяться на то, что ваши выпадающие меню работают на устройствах с тач-экранами. Вы определенно можете сделать так, чтобы это было правдой! Вы также поступите правильно, если захотите собрать весь ваш код вместе в целях повышения эффективности или будете загружать скрипты и стили только при необходимости благодаря определению возможностей (или и то и другое одновременно).
Доступность навигации с клавиатуры является еще одной классической проблемой выпадающих меню. Мне просто не хочется, чтобы вы думали, что, решив проблему с перемещением курсора мыши, вам больше ничего не придется делать для улучшения пользовательского опыта взаимодействия при работе с выпадающими меню. Всегда есть возможность что-то улучшить!
Автор: Chris Coyier
Источник: //css-tricks.com/
Редакция: Команда webformyself.