Can I forcibly ignore the: hover pseudo-vector for iPhone / iPad users?

I have some css menus on my site that expand with :hover (without js)

This works in a semi-ruined way in iDevices, for example, clicking activates the rule :hover and expands the menu, but then clicking elsewhere does not delete :hover . Also, if there is a link inside the element :hover 'ed, you need to double-click to activate the link (first triggers :hover , second trigger key).

I managed to get everything working on the iphone by attaching a touchstart event.

The problem is that sometimes mobile safari still chooses the rule to run :hover from css instead of from my touchstart events!

I know this is a problem because when I turn off all the rules :hover manually in css, mobile safari works fine (but regular browsers obviously don't work anymore).

Is there a way to dynamically “cancel” :hover rules for certain elements when the user is on a mobile safari?

See and compare iOS behavior here: http://jsfiddle.net/74s35/3/ Note: only some css properties trigger two-click behavior, for example. Display: no; but not the background: red; or text design: underline;

+84
iphone pseudo-class mobile-safari ipad
Apr 30 2018-10-10T00:
source share
13 answers

I found that ": hover" is unpredictable in iPhone / iPad Safari. Sometimes tap on element makes this element ": hover", sometimes it drifts to other elements.

Currently, I just have a no-touch class in the body.

 <body class="yui3-skin-sam no-touch"> ... </body> 

And all the CSS rules with the caption ": hover" below ".no-touch":

 .no-touch my:hover{ color: red; } 

Somewhere on the page, I have javascript to remove a class without touching the body.

 if ('ontouchstart' in document) { Y.one('body').removeClass('no-touch'); } 

It doesn't look perfect, but it works anyway.

+69
Jan 19 '11 at 10:22
source share

:hover is not a problem here. Safari for iOS follows a very strange rule. First, it launches mouseover and mousemove ; if nothing has changed during these events, 'click' and related events do not fire:

Diagram of touch event in iOS

mouseenter and mouseleave appear to be included, although they are not shown in the diagram.

If you change anything as a result of these events, click events will not fire. This includes something higher in the DOM tree. For example, this will prevent one-click execution of your site using jQuery:

 $(window).on('mousemove', function() { $('body').attr('rel', Math.random()); }); 

Edit: For clarification, the jQuery hover event includes mouseenter and mouseleave . They will prevent click if the content is modified.

+36
Sep 20 '13 at 8:32
source share

Browser Feature Detection Library The Upgrader includes touch event verification.

Its default behavior is to apply classes to your html element for each function detected. Then you can use these classes to create the document.

If touch events are not enabled, Modernizr can add a no-touch class:

 <html class="no-touch"> 

And then expand the hover styles with this class:

 .no-touch a:hover { /* hover styles here */ } 

Download your own Modernizr build to include as few or as many features as possible.

Here is an example of some classes that can be applied:

 <html class="js no-touch postmessage history multiplebgs boxshadow opacity cssanimations csscolumns cssgradients csstransforms csstransitions fontface localstorage sessionstorage svg inlinesvg no-blobbuilder blob bloburls download formdata"> 
+18
Jan 29 '13 at 23:54
source share

Some devices (as others have said) have both touch and mouse events. For example, the Microsoft Surface has a touch screen, trackpad, and stylus that actually raises hover events when it hangs over the screen.

Any solution that disables :hover based on the presence of touch events also affects Surface users (and many other similar devices). Many new laptops are touching each other and will respond to touch events - so disabling freezing is really bad practice.

This is a bug in Safari, absolutely no excuse for this terrible behavior. I refuse to sabotage non-iOS browsers due to a bug in iOS Safari that has obviously been there for years. I really hope they fix it for iOS8 next week, but in the meantime ....

My decision:

Some have suggested using Modernizr already; well, Modernizr allows you to create your own tests. What I mostly do here is abstracting the idea of ​​a browser that supports :hover in the Modernizr test, which I can use in all my code without hard coding if (iOS) .

  Modernizr.addTest('workinghover', function () { // Safari doesn't 'announce' to the world that it behaves badly with :hover // so we have to check the userAgent return navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? false : true; }); 

Then css becomes something like this

 html.workinghover .rollover:hover { // rollover css } 

Only on iOS will this test fail and disable rollover.

The best part of such an abstraction is that if I find that it breaks on a specific android or if it is fixed in iOS9, then I can just change the test.

+16
Sep 14 '14 at 19:45
source share

Adding the FastClick library to your page will turn all the taps on the mobile device into click events (no matter where the user clicks), so it should also fix the problem with freezes on mobile devices. As an example, I edited your fiddle: http://jsfiddle.net/FvACN/8/ .

Just include fastclick.min.js lib in your page and activate with:

 FastClick.attach(document.body); 

As a side benefit, it will also eliminate the annoying 300ms delay when mobile devices suffer.


There are a few minor implications for using FastClick that may or may not matter to your site:

  • If you click anywhere on the page, scroll up, scroll back, and then release your finger in the same place where you placed it, FastClick interprets this as a “click”, although this is clearly not the case. At least how it works in the version of FastClick that I am currently using (1.0.0). Maybe someone fixed the problem with this version.
  • FastClick removes the double-click option for someone.
+14
Jul 01 '13 at 23:06 on
source share

Basically three scenarios:

  • The user only has a mouse / pointer device and can activate :hover
  • The user has only a touch screen and cannot activate elements :hover
  • The user has both a touch screen and a pointing device

The initially accepted answer works fine if only the first two scenarios are possible, where the user has either a pointer or a touch screen. This was commonplace when the OP asked the question 4 years ago. Several users have indicated that Windows 8 and Surface devices make the third scenario more likely.

IOS's solution to the problem of impossibility of pointing to touch devices (as described in @Zenexer) is smart, but can lead to the fact that simple code will be erroneous (as noted by OP). Turning off hovering only for touchscreen devices means that you still have to code for an alternative with a touchscreen. Detection when the user has both a pointer and a touch screen additionally mixes water (as explained by @Simon_Weaver).

At this stage, the safest solution is to refuse to use :hover as the only way for the user to interact with your site. Hover effects are a good way to show that a link or button is valid, but the user does not need to hover over an element to perform actions on your website.

Rethinking the hover functionality based on touch screens provides a good discussion of alternative UX approaches. The solutions provided by the answer include:

  • Replacement of the guidance menu with direct actions (always visible links)
  • Replacing hover menus using context menus
  • Move a large amount of content on a separate page

Moving forward, this is likely to be the best solution for all new projects. The accepted answer is probably the second best solution, but be sure to consider devices that also have pointing devices. Be careful not to eliminate functionality when the device has a touch screen to get around iOS :hover hack.

+4
Dec 28 '14 at 20:36
source share

Best solution without checking JS, css and viewport: you can use Media Media features (Media Queries Level 4)

Like this:

 @media (hover) { // properties my:hover { color: red; } } 

iOS Safari supports it

Read more about: https://www.jonathanfielding.com/an-introduction-to-interaction-media-features/

+4
Nov 15 '16 at 19:08
source share

The jQuery version in your use of .css.no-touch.my-element: hover for all hover rules includes jQuery and the following script

 function removeHoverState(){ $("body").removeClass("no-touch"); } 

Then in the body tag add class = "no-touch" ontouchstart = "removeHoverState ()"

as soon as ontouchstart starts the class for all hover states, it is deleted

+1
Jul 08 2018-11-18T00:
source share

Instead of having only freezing effects when touch access is unavailable, I created a touch event processing system, and this solved the problem for me. First, I defined an object to test for tap events (equivalent to click).

 touchTester = { touchStarted: false ,moveLimit: 5 ,moveCount: null ,isSupported: 'ontouchend' in document ,isTap: function(event) { if (!this.isSupported) { return true; } switch (event.originalEvent.type) { case 'touchstart': this.touchStarted = true; this.moveCount = 0; return false; case 'touchmove': this.moveCount++; this.touchStarted = (this.moveCount <= this.moveLimit); return false; case 'touchend': var isTap = this.touchStarted; this.touchStarted = false; return isTap; default: return true; } } }; 

Then in my event handler, I do something like the following:

 $('#nav').on('click touchstart touchmove touchend', 'ul > li > a' ,function handleClick(event) { if (!touchTester.isTap(event)) { return true; } // touch was click or touch equivalent // nromal handling goes here. }); 
+1
Jun 21 '12 at 1:50
source share

Thanks to @Morgan Cheng for the answer, however I changed the JS function a bit to get "touchstart" (code taken from @Timothy Perez answer ), although you need jQuery 1.7+ for this

  $(document).on({ 'touchstart' : function(){ //do whatever you want here } }); 
0
Nov 20 '13 at 12:52
source share

Given the answer provided by Zenexer, a template that does not require additional HTML tags is as follows:

 jQuery('a').on('mouseover', function(event) { event.preventDefault(); // Show and hide your drop down nav or other elem }); jQuery('a').on('click', function(event) { if (jQuery(event.target).children('.dropdown').is(':visible') { // Hide your dropdown nav here to unstick } }); 

This method first starts the mouse pointer, and then a second click.

0
Jun 03 '14 at 5:58
source share

Just look at the screen size ....

 @media (min-width: 550px) { .menu ul li:hover > ul { display: block; } } 
-6
Mar 19 '15 at 8:49
source share

enter the code you want to put in

 // a function to parse the user agent string; useful for // detecting lots of browsers, not just the iPad. function checkUserAgent(vs) { var pattern = new RegExp(vs, 'i'); return !!pattern.test(navigator.userAgent); } if ( checkUserAgent('iPad') ) { // iPad specific stuff here } 
-12
Jun 09 2018-10-06T00:
source share



All Articles