12
\$\begingroup\$

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 <body> element):

<div class="menuitem">
    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>
<h1>Heading</h1>
<p>Lorem ipsum.</p>

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:

Furthermore the Mozilla help says not to rely on hover:

On touch screens :hover is problematic or impossible. The :hover pseudo-class never matches, or matches for a short moment after touching an element. As touchscreen devices are very common, it is important for web developer not to have content accessible only when hovering over it, as this content would be hidden for users of such devices.

However, this code I posted seems to work, so I don't know what's wrong with it or how to fix it.

Articles like How to deal with :hover on touch screen devices and iOS has a :hover problem suggest that :hover is supported on touch screens but that it causes "double tap behavior on touch screens".

Am I right in thinking that:

  • :hover is reliably synthesized on touch screen devices
  • I am expecting/requiring the user to double-touch (once to open the submenu and a second time to touch a link inside the submenu) and therefore "double tap behavior" isn't a problem.
\$\endgroup\$
4
  • \$\begingroup\$ First, using -999em paints a very large and taxing element, use -100% or the exact width of the element instead. Second, a hover state is two part, which is why you may need to touch and hold to retain the hover state on some devices and double tap on others, it's inconsistent. I'd check the jquery I used here: stackoverflow.com/a/24461740/2134533 it can easily be adapted to work and allows for greater control over the different states. \$\endgroup\$
    – darcher
    Jul 7, 2014 at 8:09
  • \$\begingroup\$ After looking at your example I was wondering how to make handling touch events compatible with also handling hover events (because it's supposed to work with both/either). One possibility (which I haven't tested) might be something like jsfiddle.net/i_like_robots/6JbtX/light which handles mouseover and touchstart (distinct events) instead of handling hover (an ambiguous event) at all. \$\endgroup\$
    – ChrisW
    Jul 7, 2014 at 10:14
  • \$\begingroup\$ @ChrisW This does not work at all on my iPhone, not on Safari nor on Chrome for iPhone. \$\endgroup\$
    – konijn
    Jul 8, 2014 at 18:23
  • \$\begingroup\$ This should be possible with Media Queries - developer.mozilla.org/en-US/docs/Web/Guide/CSS/Media_queries and jQuery - jquery.com The idea would be to swap the :hover support to click support dependent on the device being used or even swap the menu out completely to a jQuery dropdown menu on mobile devices. \$\endgroup\$
    – CodeX
    Jul 10, 2014 at 11:27

2 Answers 2

5
+500
\$\begingroup\$

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 <body ontouchstart="">. 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 ).

<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>

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.

\$\endgroup\$
1
\$\begingroup\$

For what it's worth, I just encountered this issue today.

I came to the conclusion that it's not worth using :hover to target things for events because it's too wonky on mobile. In my case the double tap was causing issues.

The only functionality that you mentioned which my menu currently doesn't have is to close when touched anywhere outside the menu. I'm sure it wouldnt be hard to add.

However, I'm not sure if you wanted to avoid javascript/jQuery. I too wanted to avoid this in the beginning, but the solution I came up with ended up using them.

I tested your code on my iPhone in safari and it does seem to function.

Here is a link to my code review, which also has a demo if you want to take a look.

CSS3 Dropdown Menu (touch device or mouse compatible)

the jQuery required:

//click to open menu
$('.follow button').click(function(){
    $('.addClass').toggleClass("profile-container");
});

I used CSS3 transitions to animate my drop down menu. In their default position, the list items are hidden by a transform.

I original was using a :hover to control the animation that showed the li's, but instead of that I targeted them by class, and use jQuery to add and remove the class on click of a button. This kept my animations in tact and works on my iPhone safari, cheap Droid and chrome, and my laptop with touch screen.

If you'd like the files: https://github.com/agraymd/Animated-Profile-Menu

Working Demo: http://jsfiddle.net/tddfevhv/1/

Original Idea: http://codepen.io/mariusbalaj/pen/rtwAI

^^ I thought that codepen wouldn't close on mobile, but after I tried again that one closes when you click out. And it hovers on desktop. So that's exactly what you need with no javascript.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.