ftlabs / fastclick

Polyfill to remove click delays on browsers with touch UIs
MIT License
18.66k stars 3.23k forks source link

Tapping triggers hover event on other elements #83

Closed peterostrander closed 11 years ago

peterostrander commented 11 years ago

I'm seeing an issue where tapping on the screen can sometimes trigger the css :hover state of an element outside of that tap. I've uploaded a video of what I'm seeing in the iPhone Simulator. I'm getting the same bug on my iPhone 5.

http://www.screencast.com/t/poflecU6OX

mattcg commented 11 years ago

Thanks for reporting and for the screencast. That is indeed very unusual! Are you using any scrolling frameworks like iScroll or Sencha Touch Scroller that might be 3D-transforming the 'scrolling' layer?

peterostrander commented 11 years ago

No scrolling frameworks at all. I put together a very simple page to demonstrate what's happening. It just has some css, fastclick.js, and the fastclick instantiation code in the <head>. It's almost like it's ghosting the element on page load. Wherever that element existed relative to the window, :hover is triggered on that element when you click within that window space.

Here's another video for the simple site example: http://www.screencast.com/t/LGsImLH4JaC5

And here's a link to the page: http://fastclick-issue83.aws.af.cm/

Thanks!

dryabov commented 11 years ago

I was able to reproduce it on Android: 1) click on "button" to focus it, 2) click outside button to switch its hover state.

Sequence of events on step # 2 is the following (here A and DIV are event targets):

touchstart DIV mousemove A touchend DIV click DIV DOMActivate DIV

To me it looks like something browser-specific (and I have the same behaviour without FastClick).

PS. Test page I used is here: http://jsfiddle.net/dryabov/kYSQL/

mattcg commented 11 years ago

Thank you for the screencast and example @peterostrander. I've managed to replicate on iOS 6.1 and 5.1 and am looking into the problem.

mattcg commented 11 years ago

This is a browser bug. I've added a reduced test case in tests/83-reduced.html that shows that the issue can be replicated without FastClick. Adding an a touchend listener is all that's needed.

As a temporary workaround I recommend that you avoid adding :hover styles on mobile. There are some other reasons for doing this, and a method showing how to do it, in this article.

peterostrander commented 11 years ago

Thanks for the suggestion @mattcg. I went ahead and stripped out :hover styles on mobile and that's taken care of the issue.

mattcg commented 11 years ago

No probs. Please file again if you find any other issues.

PathbriteJustin commented 11 years ago

Just curious, has anyone come across a solution to this bug without removing :hover styles on mobile?

ixisio commented 10 years ago

think you have to check if it's a touch or non-touch device, not if it's a mobile device or not.

RGBboy commented 10 years ago

I have found a solution that does not require removing the :hover styles on mobile. The solution was inspired by this article: http://www.thecssninja.com/javascript/pointer-events-60fps

The problem can be fixed by adding the css property pointer-events:none on touchstart and preventing default on the touchstart event for the element you don't want the hover to affect. The pointer-events:none should be removed on touchend. For example with jqlite:

var body = document.find('body');

document.on('touchstart', function (event) {
  body.css('pointer-events', 'none');
});

document.on('touchend', function (event) {
  body.css('pointer-events', '');
});

Then you need to cancel the touchstart event on the elements you want to stop:

element.on('touchstart', function (event) {
  event.preventDefault();
});

Be careful though, if you prevent default on a anchor element, the link will not be followed.

Currently I have only tested this on iOS 6 safari and chrome.

nspo commented 7 years ago

Had the same problem on an iPad 1 (iOS 5) with Bootstrap 3 and buttons as checkboxes. The following CSS and JS works for me:

.disable-hover {
  pointer-events: none;
}

and

/* Add workaround for fastclick.js hover issue: https://github.com/ftlabs/fastclick/issues/83 */
var body = document.body;

window.addEventListener('touchstart', function () {
    if (!body.classList.contains('disable-hover')) {
        body.classList.add('disable-hover');
    }

}, false);

window.addEventListener('touchend', function () {
    if (body.classList.contains('disable-hover')) {
        body.classList.remove('disable-hover');
    }

}, false);