Simple touch-friendly HTML menus (using javascript)

By devin, 27 October, 2015

I have a website with a two-level dropdown menu (it's not this one!). I want it to be slick, so I used CSS to only show the submenus when the user was hovering on the relevant parent menu item. This was great, until I realized people liked to access my website from their phones. The only way to reveal the submenus using a touch screen is to click the top menu item, but that will activate the link and change the page before you can find the link you want.

I looked at a few things, including doubletaptogo.js. They were either too complicated or didn't work (doubletaptogo.js fell into the latter category; I may have been able to get it to work if I rearchitected the site's entire theme to move the menu into a specific position).

Here is what I eventually came up with. Imagine a menu with this HTML:

<ul id="menu">
  <li id="menu-1">
    <a href="#">Item 1</a>
    <ul id="submenu1">
      <li id="submenu1-1><a href="#">Submenu 1 Item</a></li>
      <li id="submenu1-2><a href="#">Submenu 1 Item</a></li>
  </ul></li>
  <li id="menu-2">
    <a href="#">Item 2</a>
    <ul id="submenu2">
      <li id="submenu2-1><a href="#">Submenu 2 Item</a></li>
      <li id="submenu2-2><a href="#">Submenu 2 Item</a></li>
  </ul></li>
</ul>

 

My pre-existing CSS did this:

#menu li > ul {
  display: none;
}

#menu li:hover > ul {
  display: block;
} 

 

This is great; the submenus appear when you hover with this CSS alone. You need a bit more to make it nice, but then you can worry about phones.

To modify this to work with touch screens and Desktops (fairly) well, I added a javascript file with the following code (requires jQuery):

$(document).ready(function() {
  //set all top-level li tags to be unselected, in the view of this code
  $('#menu > li').attr('menu-selected', 'false');

  //if you click a li tag (mobile or desktop), either add the menu-selected
  //attr OR do the default behaviour (go to the link)
  $('#menu-main-nav > li').click(function(e) {
    if($(this).attr('menu-selected') === 'true') {
      return true; //default behaviour -> open the link
    }
    e.preventDefault();

    $('#menu-main-nav > li').attr('menu-selected', 'false');
    $(this).attr('menu-selected', 'true');
    return false;
  });

  //emulate hover for desktop users
  $('#menu-main-nav > li').mouseenter(function(e) {
    $(this).attr('menu-selected', 'true');
  });
  $('#menu-main-nav > li').mouseleave(function(e) {
    $(this).attr('menu-selected', 'false');
  });
});

 

Then you need to slightly adapt your CSS:

#menu li:hover > ul {
  display: none; /* override old behaviour */
}
#menu li[menu-selected=true] > ul {
  display: block;
}

 

This isn't super elegant or beautiful, but it is very easy to encapsulate into one file and put into an existing codebase. That's what I wanted, and it works well!

Plain text

  • No HTML tags allowed.
  • Web page addresses and email addresses turn into links automatically.
  • Lines and paragraphs break automatically.