A website I have designed uses a nav menu that shows submenus on :hover
. The initial site did not use any responsive design: it targeted only the desktop environment. I am now using responsive-design techniques to target mobile devices and tablets, many of which are touch based rather than mouse based.
The big issue I was facing (and that many other people seem to have also faced) was the hover-based nav menu: it works great in a mouse environment, but on touch devices, there is no reliable way to trigger the hover, making the page difficult to use.
The goal is this:
- When a menu is hovered by a mouse, show the sub-menu.
- When a menu is clicked with a mouse, open the link of the anchor tag.
- The first time a menu is clicked by touch, show the sub menu.
- The second time a menu is clicked by touch, open the link of the anchor tag.
- Switch functionality seamlessly for tablets that also have mouse devices attached.
My team is not willing to sacrifice the hover effect on mouse-based machines. They like it and do not want to make the menus click based on all devices. I agree with this.
After looking around the net, I couldn't find any single solution for my problem. I put a few of them together and developed something that has tested well on Android, getting exactly the functionality I wanted. Is there anything that can be improved and/or do you see any problems with this approach?
jQuery(document).ready(function() {
var touched=false;
jQuery(".nav").on('touchstart', 'li .has_children', function (e) { touched=true; });
jQuery("html").on('mousemove', function (e) { touched=false; });
jQuery("html").on('click', updatePreviousTouched );
jQuery(".nav").on('click', 'li .has_children', function (e) {
updatePreviousTouched(e);
if( touched ) {
if (jQuery(this).data('clicked_once')) {
jQuery(this).data('clicked_once', false);
return true;
} else {
e.preventDefault();
jQuery(this).trigger("mouseenter");
jQuery(this).data('clicked_once', true);
}
}
touched=false;
});
var previous_touched;
function updatePreviousTouched(e) {
if( typeof previous_touched != 'undefined' && previous_touched != null && !previous_touched.is( jQuery(e.target) ) ) {
previous_touched.data('clicked_once', false);
}
previous_touched=jQuery(e.target);
}
}
If this solution can be improved, please provide any suggestions. If you find that it doesn't work for you, please let me know that too. I'm posting it here to try to get any suggestions for improvement and to publish the idea so others can benefit from it.
Here are the results of my tests so far:
- Windows 7 on major 5 browsers: works.
- Android tablet on default browser: works.
- Windows 7 laptop with touch-screen on IE and Chrome: Sort-of-works. The machine is running the desktop version of both browsers, so it is not triggering the "touchstart" event. Somewhere between the touchscreen and the browser, something is converting the touch into mouse events. However, since the mouse is a non-removable part of this device, I don't consider this a failure. I would like it if it worked like a tablet, but there doesn't seem to be the technology available yet.
- iOS iPad: This worked as desired before I wrote the above javascript. It appears that ios does some of this hover/click magic for us behind the scenes. I have a team member checking to see if my javascript broke the iOS functionality, I will edit this post once I get an answer.
Other notes:
- This is only the menu for the desktop and tablet site. There is a different, click-based menu for the mobile site. I wouldn't recommend using this solution for a phone-sized device.