1

I've got the following problem with a menu on a responive website:

I created a html menu which has ul/li-structure which contains links as category-names

<ul>
    <li>
       <a href="linkToCat">maincat1</a>
        <ul>
            <li>
                <a href="linkToCat">subcat1.1</a>
                <ul>
                    //deeper category stucture
                </ul>
            </li>
        </ul>
    </li>
    <li>
       <a href="linkToCat">maincat2</a>
        <ul>
            <li>
                <a href="linkToCat">subcat2.1</a>
            </li>
            <li>
                <a href="linkToCat">subcat2.2</a>
            </li>
        </ul>
    </li>
</ul>
<style>
    li > ul {
        display:none;
    } 

    li:hover > ul {
        display:block;
    } 
</style>

I am only showing the maincats at the beginning and the the subcats open on hover as shown in this JSFiddle.

Everything just works fine on desktop. The problem is that it doesnt work on touch-devices (e.g. smartphones/tablets) as soon as I use links as the names of the categories (Which I need to do).

Is there any way to make a menu that works with hover on desktop and that is still useable on touch-devices when using links as categorynames?

I got no problem about using JavaScript or jQuery to solve this problem. Normally I am using a responsive design with a extram menu for smartphones or other mobile devices. Therefor I am using @media screen. This sadly doesn't work with all touch devices like for example bigger tablets like some iPads or the microsoft surface.

Thank you for your answers and hints.

Edit: The problem is the <a href> The link always get triggert and so the menu doesn't open when i click on a category. I now also have added links to the categorynames in the JSFiddle

Yannick Huber
  • 607
  • 2
  • 16
  • 35

4 Answers4

2

Workaround with doubleclick for touch-devices

I now found a solution for my problem by adding the following JavaScript

The idea of how to dectect if the device is a touch device is based on this answer.

$(document).ready(function(){
    //added for surface
    window.USER_IS_TOUCHING = false;
    window.addEventListener('touchstart', function onFirstTouch() {
        window.USER_IS_TOUCHING = true;
        // we only need to know once that a human touched the screen, so we can stop listening now
        window.removeEventListener('touchstart', onFirstTouch, false);
    }, false);

    function isTouchDevice() {
      return 'ontouchstart' in window        // works on most browsers 
          || navigator.maxTouchPoints;       // works on IE10/11 and Surface
    };
    $('ul > li > a').click(function(e){
        var target = $(e.target);
        var parent = target.parent(); // the li
        if(isTouchDevice() || window.USER_IS_TOUCHING){
            if(target.hasClass("active")){
                //run default action of the link
            }
            else{
                e.preventDefault();
                //remove class active from all links
                $('ul > li > a.active').removeClass('active');
                //set class active to current link
                target.addClass("active");
                parent.addClass("active");
            }
        }
    });
    $('ul > li').click(function(e){
        //remove class active from all links if li was clicked
        if (e.target == this){
            $(".active").removeClass('active');
        }
    });
});

And the following css

.active > ul >li{
    display:block;
}

Now the first click of a touch device opens the submenu while a doubleclick runs the default action of the link.

I have tested this solution on an android smartphone & tablet and also on iphone & ipad. I havn't had the possibility to test it on a touchlaptop or microsoft surface yet. If anyone has: feel free to write a comment

Here's an example JsFiddle

Or you can also try it out here:

$(document).ready(function(){
 window.USER_IS_TOUCHING = false;
 window.addEventListener('touchstart', function onFirstTouch() {
    window.USER_IS_TOUCHING = true;
   // we only need to know once that a human touched the screen, so we can stop listening now
   window.removeEventListener('touchstart', onFirstTouch, false);
 }, false);

  function isTouchDevice() {
    return 'ontouchstart' in window        // works on most browsers 
        || navigator.maxTouchPoints;       // works on IE10/11 and Surface
  };
  $('ul > li > a').click(function(e){
      var target = $(e.target);
      var parent = target.parent(); // the li
      if(isTouchDevice() || window.USER_IS_TOUCHING){
          if(target.hasClass("active")){
              //run default action of the link
          }
          else{
              e.preventDefault();
              //remove class active from all links
              $('ul > li > a.active').removeClass('active');
              //set class active to current link
              target.addClass("active");
              parent.addClass("active");
          }
      }
  });
  $('ul > li').click(function(e){
    //remove class active from all links if li was clicked
    if (e.target == this){
      $(".active").removeClass('active');
    }
  });
});
li > ul {
  display:none;
} 

li:hover > ul {
  display:block;
} 

.active > ul >li{
  display:block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
        <li>
            <a href="stackoverflow.com">maincat1</a>
            <ul>
                <li>
                    <a href="stackoverflow.com">subcat1.1</a>
                    <ul>
                        <li>
                            subcat1.1.1
                        </li>
                        <li>
                            subcat1.1.2
                        </li>
                    </ul>
                </li>
            </ul>
        </li>
        <li>
            <a href="stackoverflow.com"> maincat2</a>
            <ul>
                <li>
                    subcat2.1
                </li>
                <li>
                    subcat2.2
                </li>
                <li>
                    subcat2.3
                     <ul>
                        <li>
                            subcat2.3.1
                        </li>
                        <li>
                            subcat2.3.2
                        </li>
                    </ul>
                </li>
            </ul>
        </li>
    </ul>
Yannick Huber
  • 607
  • 2
  • 16
  • 35
1

Whatever you are doing should work on touch devices. But here is another way to do it using jQuery.

$('li').click(function(e){
    $(this).children('ul').toggle();
    e.stopPropagation();
});

Run the following code snippet to see. I have commented css property on hover display none so that you can have better understanding of jQuery code. Uncommenting it will also work fine.

$('li').click(function(e){
 $(this).children('ul').toggle();
  e.stopPropagation();
});
li > ul {
  display:none;
} 

/*li:hover > ul {
  display:block;
}*/
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
  <li>
      maincat1
      <ul>
          <li>
              subcat1.1
              <ul>
                  <li>
                      subcat1.1.1
                  </li>
                  <li>
                      subcat1.1.2
                  </li>
              </ul>
          </li>
      </ul>
  </li>
  <li>
      maincat2
      <ul>
          <li>
              subcat2.1
          </li>
          <li>
              subcat2.2
          </li>
          <li>
              subcat2.3
               <ul>
                  <li>
                      subcat2.3.1
                  </li>
                  <li>
                      subcat2.3.2
                  </li>
              </ul>
          </li>
      </ul>
  </li>
</ul>
vatz88
  • 2,422
  • 2
  • 14
  • 25
0
cursor: pointer

This fixes most of the problems with hover on mobiles.

By the way - your fiddle works fine on my Android device (Huawei Honor 4C).

@edit: add cursor: pointer on <ul> element

pzworks
  • 165
  • 2
  • 8
-1

You can try using superfish

It worked for me for my hover menu.

dannio
  • 900
  • 8
  • 12