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:
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);
}
}
Here's a jfiddle: http://jsfiddle.net/5FfCF/1/
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:
Other notes:
Before you read this wall of text, check out the fiddle and make sure it's what you're looking for. Test on a phone too (I tested on my Android and had no issues).
If you have a completely separate set of code for mobile phones, then you have nothing to worry about really. Adapting to the touch vs. hover event is particularly tricky on iOS devices. But I was able to overcome this by capturing a range of mouse events that translated to a touch event.
For your particular case, since you want this to be so different between the three, I would suggest running an early script to get the screen size and if it's less than ### px x ### px
, add a class called handheld
or mobile
or whatever to body
. Now all you have to do is assign the touch
capture code to $('.mobile .nav')
and have a separate piece of code assigning the hover
event to PCs.
For tablets, you'll have to decide what's more important to you - the ability to click and navigate using the root menu item for each menu, or only allowing a click on the sub-menu items (which would eliminate the need to add the .mobile
class to body
).
Here's some code that you should be able to use on both mobile and desktop.
jQuery(document).ready(function () {
$('.nav').on('click mousedown mouseup touchstart touchmove', 'a.has_children', function () {
if ( $(this).next('ul').hasClass('open') && !$(this).parents('ul').hasClass('open')) {
$('.open').removeClass('open');
return false;
}
$('.open').not($(this).parents('ul')).removeClass('open');
$(this).next('ul').addClass('open');
return false;
});
$(document).on('click', ':not(.has_children, .has_children *)', function() {
if( $('.open').length > 0 ) {
$('.open').removeClass('open');
return false;
}
});
});
Normally I don't copy all the HTML like I'm about to do but in this particular instance you'll need to take it exactly as I have it here to avoid the inline-block
white-space glitch. Compare my fiddle to your original and see how much easier it is to hover/click on each link.
<div class="header-nav-menu">
<ul class="nav">
<li><a href="http://www.google.com">One</a></li><li>
<a class="has_children" href="http://www.google.com">Two</a>
<ul>
<li><a href="http://www.google.com">2A</a></li><li>
<a href="http://www.google.com">2B</a>
</li>
<li><a href="http://www.google.com">2C</a>
</li>
</ul>
</li><li>
<a class="has_children" href="http://www.google.com">Three</a>
<ul>
<li><a href="http://www.google.com">3A</a>
</li>
<li> <a class="has_children" href="http://www.google.com">3B</a>
<ul>
<li><a href="http://www.google.com">3BI</a>
</li>
<li><a href="http://www.google.com">3BII</a>
</li>
<li><a href="http://www.google.com">3BIII</a>
</li>
</ul>
</li>
<li><a href="http://www.google.com">3C</a>
</li>
</ul>
</li><li>
<a href="http://www.google.com">Four</a></li><li>
<a href="http://www.google.com">Five</a></li>
</ul>
</div>
Pretty sure I didn't even touch the CSS so I'll leave that in the Fiddle for now. Hopefully this helps you on your way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With