Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mobile (touch) device friendly drop down menu in css / jquery

I have been reading many topics on this subject, a drop down menu which is friendly on mobile devices. Many times it is considered best to have a non-hover action on the drop down menu. There are workarounds, with one being that the main hyperlink for the drop down item should link to a hashtag.

This makes it work on mobile devices but for the normal desktop user, this would be confusing. So the solution would be to have a normal drop down menu for desktop users in which the first hyperlink also links to a page. For mobile users, the tap on an item will open the drop down menu, but a second tap on the main item will open the corresponding page.

I have seen the following site and somehow their menu works exactly like that: http://www.hgtv.com/ You can view this on a tablet and click on the main menu, tap that item again and you will know what i mean.

But how can i find or download the exact similar setup for my own site?

Thanks in advance

like image 971
John Avatar asked Aug 07 '12 16:08

John


2 Answers

Here's what I got working:

function isTouchDevice(){
    return typeof window.ontouchstart !== 'undefined';
}

jQuery(document).ready(function(){
    /* If mobile browser, prevent click on parent nav item from redirecting to URL */
    if(isTouchDevice()) {
        // 1st click, add "clicked" class, preventing the location change. 2nd click will go through.
        jQuery("#menu-main-menu > li > a").click(function(event) {
            // Perform a reset - Remove the "clicked" class on all other menu items
            jQuery("#menu-main-menu > li > a").not(this).removeClass("clicked");
            jQuery(this).toggleClass("clicked");
            if (jQuery(this).hasClass("clicked")) {
                event.preventDefault();
            }
        });
    }
});

I'm using this for my WordPress site. On desktop browsers (non-touch browsers), when the main menu item is clicked, it will go straight to the link's location. When hovered, it will show the dropdown.

For mobile (touch browsers), when the main menu item is touched, it will expand the dropdown, and if clicked again it will go to the new location. I also added a "reset" line of code to get this part working: if you touch the first main menu item (expanding the dropdown), then touch the second main menu item (expanding the 2nd dropdown), then touch the first main menu item again, it will still behave as a dropdown until clicked again. Without this line, it would just proceed straight to the new location.

like image 101
Jeremy Avatar answered Sep 22 '22 06:09

Jeremy


Here is a device-agnostic technique (not sure how much I trust feature detection for this.. many modern browsers report support for touch events even if the interface is mouse) I used to make hover menus work on touchscreens as expected (ie, prevent the touch event from prematurely "clicking" the top menu link when we just want the first click to trigger a hover).

The trick is to recognize that a touch hover+click event will happen right on top of each other.. ie the hover event will be followed almost immediately by the click event. We can detect this and prevent the click from going through... only allowing the click to trigger if a certain threshold of time has elapsed since the hover event.

When testing on a desktop, I was never able to get the elapsed time faster than about 150ms between hover and click no matter how fast I clicked. When testing on on an iPad (4th gen) the elapsed time between hover & click was always around 7 - 8 ms. So I chose a threshold time of 50ms to allow clicking. The jQuery function I wrote is as follows (this assumes a standard nested-list CSS hover menu):

  function initNav(){
    // make drop-downs work properly with touchscreens by preventing instant hover-click
    $( some_selector_for_your_top_level_list_items ).each(function(){
      var li = $(this);
      li.mouseover(function(){
        // store time of hover event
        li.data( 'hoverTime', new Date().getTime() );
      });
      li.children('a').click(function(){
        // only allow click if at least 50ms has elapsed since hover
        return ( new Date().getTime() - li.data('hoverTime') ) > 50;
      });
    });
  }

Working like a charm so far. It's possible 50ms might be too low for much slower devices.

For non-JS you will still have the default CSS hover behaviour as fallback.

Hope this helps people, as I couldn't find a good drop-in solution that didn't involve questionable feature detection and/or rewriting your CSS hover behaviour using JS.

like image 26
Brian Avatar answered Sep 20 '22 06:09

Brian