I. click and 300ms Delay
Mobile browsers provide a special feature: double tap to zoom
The 300ms delay comes from here, after user touches the page, needs to wait for a period of time to judge whether it's a double tap action, instead of immediately responding to click, this waiting time is about 300ms. Previously had a brief introduction: [Anye Qingyang: HTML5 Touch Events](/articles/html5 触摸事件/)
Mobile events provide touchstart, touchmove, touchend but don't provide tap support, mainstream frameworks (libraries) all manually implement custom tap events, to eliminate 300ms delay and improve page response speed. For simple pages, can use touchstart or touchend as tap, but there are some problems, for example, finger touches target element, holds without releasing, slowly moves out of response area, will trigger touchstart event to execute corresponding event handler (shouldn't trigger), touchend event also has similar problems.
In addition, using native touch events also has click-through problem, because click is triggered about 300ms after touch series events occur, mixing touch and click will definitely cause click-through problem, detailed introduction below
II. Click-Through Problem
There are 3 types of click-through phenomena:
-
Click-through problem: Click close button on mask, after mask disappears, find that click event of element below button is triggered
Mask's close button is bound with touch event, while button's underlying element is bound with click event, after touch event triggers, mask disappears, 300ms later this point's click event fires, event's target naturally is the element below button, because button disappeared together with mask
-
Cross-page click-through problem: If button below happens to be an a tag with href attribute, then page will navigate
Because a tag navigation defaults to click event trigger, so principle is exactly the same as above
-
Another cross-page click-through problem: This time no mask, directly click in-page button to navigate to new page, then find that click event of corresponding position element in new page is triggered
Same logic as mask, if js control page navigation logic is bound on touch event, and corresponding position element in new page is bound with click event, and page completes navigation within 300ms, all three conditions met simultaneously, this situation occurs
If must subdivide, there's a fourth type, but probability is very low, that is corresponding position element in new page happens to be a tag, then continuous navigation occurs... and so on, all are click-through problems
III. Solutions
Problem is already very clear, there are many solutions, but ideas are不外乎 2 types:
- Don't mix touch and click
Since touch triggers click after 300ms, only using touch or only using click naturally won't have problems
- Consume (or say consume) the click after touch
Still use tap, just do extra processing in situations where click-through may occur, use something to block, or delay 350ms after tap before hiding mask, pointer-events, do detection in underlying element's event handler (with global flag), etc., as long as it can consume it
Detailed solutions:
- Only use touch
Simplest solution, perfectly solves click-through problem
Change all click in page to touch events (touchstart, 'touchend', 'tap'), need to特别注意a tags, a tag's href is also click, need to remove and change to js-controlled navigation, or directly change to span + tap control navigation. If requirements are not high, don't care about sliding out or sliding in triggering events, span + touchend is fine, after all tap needs to import third-party library
Not using a tags is actually nothing, mobile app development doesn't need to consider SEO, even if using a tags, generally will remove all default styles, might as well use span directly
- Only use click
Worst strategy, because it brings 300ms delay, any custom interaction in page will add 300ms delay, just thinking about it feels slow
Not using touch won't have problem of click triggering 300ms after touch, if interactivity requirements are not high can do this, strongly not recommended, faster is always better
- Use something to block
Relatively stupid method, never use
Ye Xiaochai's "chrysanthemum" method, for more information please see 【Mobile Compatibility Problem Research】JavaScript Event Mechanism Detailed Explanation (Involving Mobile Compatibility)
- Delay 350ms after tap before hiding mask
Minimal changes, disadvantage is hiding mask becomes slow, 350ms can still feel slow
Only need to handle mask, changes are very small, if requirements are not high, using this is more labor-saving
- pointer-events
Relatively troublesome and has defects, not recommended
After mask hides, add pointer-events: none; style to element below button, let click pass through, remove this style after 350ms, restore response
Defect is within 350ms after mask disappears, user can see element below button unresponsive when clicked, if user hand speed is very fast will definitely discover
- Do detection in underlying element's event handler (with global flag)
Relatively troublesome, not recommended
Global flag records button click position (coordinate point), judge event's coordinate point in underlying element's event handler, if same then it's that damn click, refuse to respond
Above is just idea, haven't tested, if really can't then use record timestamp to judge, wait 350ms, this way is similar to pointer-events
- fastclick
Good solution, if don't mind loading a few more KB, not recommended, because someone encountered bugs, for more information please see: Fastclick Causes click Event to Trigger Twice Problem
First import fastclick library, then change all touch events in page to click, actually slightly troublesome, suggest importing these few KB just to solve click-through problem is not worth it, might as well use first method
IV. DEMO
Wrote quite a few test pages, please see: Git @OSC ayqy / my.js
References
- Several senior blog posts
No comments yet. Be the first to share your thoughts.