1

I am trying to create a menu button that when hovered, reveals a drop down set of links on desktop. However, obviously users can't hover on mobiles etc. so have been trying to work out how to make the button reveal the menu on click too.

I have so far managed to come up with adding and removing the .show-nav class on mouse enter and leave using jquery. I tried adding the following code block but it obviously also affects desktop, which makes the menu kinda screwy if someone clicks the button (as the class is applied on the hover and then added and removed permanently using the click).

Thanks to cesare everything is working as it should, apart from in Chrome on iOS. djtwigg's solution is working in Chrome but not safari. Is it possible to merge the two solutions together?

<nav>
    <ul>
        <li id="nav-button">
            <a id="nav-click" href="#">Menu <i class="fa fa-bars"></i></a>
            <ul class="sub-nav">
                <li><a href="#">Link1</a></li>
                <li><a href="#">Link2</a></li>
                <li><a href="#">Link3</a></li>
                <li><a href="#">Link4</a></li>
            </ul>
        </li>
    </ul>
</nav>

var flag = false;
container.bind('touchstart', function(){
if (!flag) {
   flag = true;
   setTimeout(function(){ flag = false; }, 260);
   list.toggleClass('show-nav');
}
return false
});

container.hover(function(){
   list.addClass('show-nav');
}, function(){
   list.removeClass('show-nav');    
});
});
Sam Willis
  • 4,001
  • 7
  • 40
  • 59

3 Answers3

1

You can use "hover" for desktop and bind "touchstart" for mobile.

var flag = false;
container.bind('touchstart', function(){
if (!flag) {
   flag = true;
   setTimeout(function(){ flag = false; }, 260);
   list.toggleClass('show-nav');
}
return false
});

container.hover(function(){
   list.addClass('show-nav');
}, function(){
   list.removeClass('show-nav');    
});

try this fiddle: https://jsfiddle.net/62cvsvvc/6/

This solution is inspired from this question: How to bind 'touchstart' and 'click' events but not respond to both?

EDIT I checked on my server and works properly. I guess that this issue with iOS is related with jsFiddle enviroment.

Please try on: http://cesare.heliohost.org/test/

Community
  • 1
  • 1
cesare
  • 2,098
  • 19
  • 29
  • I've just tried your fiddle, unfortunately on desktop the touchstart seems to be registering as a click, which then reverses the hover effect until clicked again. Also on my iphone, I'm unable to activate the button at all but not sure why. Edit: After taking another look at the fiddle, I can't seem to recreate the reversing of the hover effect. Perhaps something hadn't loaded properly the first time. I'm still not getting any action on mobile though unfortunately. – Sam Willis Oct 21 '15 at 23:18
  • I've update the fiddle https://jsfiddle.net/62cvsvvc/6/ and now the callback is separate for avoid some bugs. Please try if accomplish now the goal. – cesare Oct 22 '15 at 07:18
  • That's working a treat on everything except IOS still. It doesn't seem to see that the click is being picked up at all. – Sam Willis Oct 22 '15 at 08:55
  • I guess the problem is related with jsFiddle enviroment. Please try on my server: http://cesare.heliohost.org/test/ If works fine, please accept the answer. – cesare Oct 22 '15 at 13:15
  • This worked perfect in safari, but has no effect in Chrome. Do you have any idea why this may be? – Sam Willis Oct 22 '15 at 13:18
  • nope, in chrome on android works correctly. Actually i can't test on chrome within iOS. – cesare Oct 22 '15 at 13:34
0

Use the touchstart event:

$('#nav-button').on('touchstart', function(){
     $('.sub-nav').toggleClass('show-nav');
});
taxicala
  • 21,408
  • 7
  • 37
  • 66
  • Unfortunately this doesn't seem to work. I believe that because the browser is registering the mouse enter just before the touch and so removes the class isntantly (as the mouseenter adds the class). – Sam Willis Oct 21 '15 at 23:11
0

It is possible to do this by checking whether the event was a touch or click. I found a plugin that helps: Gist of plugin

Simply check for a click and if it was a touch-click then toggle the menu. Use preventDefault() as shown in the fiddle. Add or remove the class on mouseenter and mouseleave by checking if it was a mouse instead of touch.

    // Bind mouse events to links.
  container
    .click(myClickCallback)
    .mouseenter(myMouseenterCallback)
    .mouseleave(myMouseleaveCallback);

  // Click callback.
  function myClickCallback(e) {
    var touchOrMouse = $body.touchOrMouse('get', e);

    // If mouse event has been invoked by touch.
    if (touchOrMouse === 'touch') {
      // Toggle .hovered class.
      list.toggleClass('show-nav');
    }

    // Do not follow the link.
    e.preventDefault();
  }

  // Mouse enter callback.
  function myMouseenterCallback(e) {
    var touchOrMouse = $body.touchOrMouse('get', e);

    // If mouse event has not been invoked by touch.
    if (touchOrMouse === 'mouse') {
      // Add .hovered class.
      list.addClass('show-nav');
    }
  }

  // Mouse leave callback.
  function myMouseleaveCallback(e) {
    var touchOrMouse = $body.touchOrMouse('get', e);

    // If mouse event has not been invoked by touch.
    if (touchOrMouse === 'mouse') {
      // Remove .hovered class.
      list.removeClass('show-nav');
    }
  }

Here is a fiddle with a working example on an iPhone: Fiddle

Daniel Twigg
  • 749
  • 4
  • 22