HiveBrain v1.2.0
Get Started
← Back to all entries
patternhtmlMinor

Mobile touch menu

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
menumobiletouch

Problem

I want to make a menu-item which:

  • Reveals a drop-down submenu, when the item is hovered (using a mouse) or touched (using a touch-screen).



  • Lets you click on a link in the submenu, while the submenu is visible



  • Closes the submenu (without clicking on a link), if you move the mouse outside the submenu (using a mouse) or touch anywhere outside the submenu (using a touch-screen).



Here's my HTML fragment (to be enclosed within HTML5 ` element):


    Drop-down menu item
    
    
        First sub-item
        Second sub-item
    

Heading
Lorem ipsum.


Here's my CSS:

div.menuitem
{
    height: 3em;
}
div.menuitem:hover ul.submenu
{
    left: auto;
}
ul.submenu
{
    left: -999em;
    z-index: 1;
    margin: 0;
    position: absolute;
    width: 10em;
    list-style: none;
    padding: 0;
    line-height: 1.6;
    background-color: Black;
}
ul.submenu a
{
    color: White;
}


The important part of the CSS is:

  • ul.submenu {left: -999em; makes the ul.submenu invisible, off to the left of the screen



  • div.menuitem:hover ul.submenu { left: auto; makes the ul.submenu visible (not off to the left of the screen) when the div is hovered.



Here is a demo.

This seems to work correctly (e.g. the submenu items become visible) when I touch it using the browser on an Android tablet.

Is the above code sufficient? If not then in what circumstance would it malfunction?

IMO, on a touch screen the browser is (or at least, all browsers that I have tried are) synthesizing a 'hover' event (and applying the hover style) when it detects a user touch.

Other solutions that I've seen on the 'net seem much more complicated than this, for example:

  • Handling Hover Events on a Touch Screen uses JavaScript



  • Click function for :hover states on touch devices suggests that it's necessary to use :focus or :active, because :hover` doesn't work.



Furthermore the Mozilla help says not to rely on hover:


On touch screens :hover is problematic or impossibl

Solution

Interesting question,

as I noted, the provided code does not work, but you can do accomplish what you tried by using :active note that this will not work without also setting `. The problem with that set up is two-fold:

  • The drop down menu item div` is still the 'owner' of the touch event, and you cannot select a sub item (lifting the finger will hide the sub-menu again, most frustrating)



  • The sub-menu items appear right under your finger, not the best user experience



Because of the 2nd problem, I think the whole mouse down and move to the right menu item does not really work for mobile (YMMV). This works fine for me ( just click to show sub items and click again to remove them ).


    Drop-down menu itemDrop-down menu item
    
    
        First sub-item
        Second sub-item
    


with toggleMenu being

function toggleMenu( menu )
{
  for (var i = 0, child ; style = menu.children[i++].style; ) 
  {
    style.left = style.left != 'auto' ? 'auto' : '-999em';
  }
}


or (less Golfic)

function toggleMenu( menu )
{
  var i = 0, 
      showValue = 'auto',
      hideValue = '-999em',
      child, style;

  while( child = menu.children[i++] ){
    style = child.style;
    style.left = style.left != showValue ? showValue : hideValue;  
  }
}


I tested ( the Golfic version, and the :active version ) on my iPhone and it does work.

Code Snippets

<div class="menuitem" onclick="toggleMenu(this)">
    Drop-down menu item<span>Drop-down menu item
    <br />
    <ul class="submenu">
        <li><a href="foo.html">First sub-item</a></li>
        <li><a href="bar.html">Second sub-item</a></li>
    </ul>
</div>
function toggleMenu( menu )
{
  for (var i = 0, child ; style = menu.children[i++].style; ) 
  {
    style.left = style.left != 'auto' ? 'auto' : '-999em';
  }
}
function toggleMenu( menu )
{
  var i = 0, 
      showValue = 'auto',
      hideValue = '-999em',
      child, style;

  while( child = menu.children[i++] ){
    style = child.style;
    style.left = style.left != showValue ? showValue : hideValue;  
  }
}

Context

StackExchange Code Review Q#56267, answer score: 5

Revisions (0)

No revisions yet.