Introduction (Foreword)

Recently, the company opened a new business line, and I was lucky to build a set of framework suitable for the new business from scratch with the big guys. As the saying goes, what suits you is the best 😎. In the CodeReview of the new project, I was mentioned by my brother whether fastClick was added to solve the 300ms delay problem on the mobile terminal. Here’s a look back at mobile latency

Introduction (the Introduction)

Past life – The cause of birth

What Exactly Is….. The 300ms Click Delay

Everything is causal, web arose in the desktop client, then who would have thought of, popular mobile devices such as mobile phones, by remember university that moment on, school sites accessed through mobile phone when 🙃 are zooming through the fingers to control, the in the mind is really ten thousand head of grass mud horse pentium, later in order to solve the problem of mobile terminal adapter, The solution of Viewport is proposed. Based on accessibility, interaction designers specially provide gesture support of double click zoom for better user experience. Little do they know that this is the root of all the trouble

This life – The fruit of death

Tap delay, gone Away

The following is a partial quote from the original

For many years, mobile browsers applied a 300-350ms delay between touchend and click while they waited to see if this was going to be a double-tap or not, since double-tap was a gesture to zoom into text.

Roughly speaking, mobile browsers wait 300-350 ms between the TouchEnd and click events to determine whether the user will double-click to scale text

Ever since the first release of Chrome for Android, this delay was removed if pinch-zoom was also disabled. However, pinch zoom is an important accessibility feature. As of Chrome 32 (back in 2014) this delay is gone for mobile-optimized sites, without removing pinch-zooming! Firefox and IE/Edge did the same shortly afterwards, and in March 2016 a similar fix landed in iOS 9.3.

From the above, we can get several very important information. First of all, Google started blowing. Since the release of chrome Mobile, as long as you turn zooming off, this delay doesn’t happen. You have to blow a Google wave, literally a few blocks ahead of Apple. FastClick source code is mostly used to solve various ios versions of all kinds of strange bugs, to tell the truth, some source CODE I am not very understand, but I dare not say what, what also dare not ask 😂. Second, Chrome 32 is optimized for mobile, so zooming doesn’t have to be a problem, and latency can also be solved. Firefox and IE/Edge followed suit, and finally, iOS 9.3 also fixed the BUG (testers did fix it)

The Resolutions are.

Here’s a hack to fix the lag without adding fastClick

Disable zoom

  • Chrome on Android (all versions)
  • IOS 9.3
<meta name="viewport" content="user-scalable=no" />
Copy the code

or

html {
  touch-action: manipulation;
}
Copy the code
  • IE on Windows Phone
html {
  touch-action: manipulation; // IE11+
  -ms-touch-action: manipulation; // IE10
}
Copy the code

Can’t help scaling

  • Chrome 32+ on Android
  • IOS 9.3
<meta name="viewport" content="width=device-width" />
Copy the code

After testing, if you do not add width=device-width, both Android and iOS versions will still have a delay problem

WebView

All of the above is for mobile browsers, since it is mobile, of course, WebView has to say

Android WebView

How to design an elegant and robust Android WebView?

The 300ms delay problem in Android WebView is the same as that in mobile browser

iOS WebView

UIWebView

In apps that run in iOS 8 and later, use the WKWebView class instead of using UIWebView. Additionally, consider setting the WKPreferences property javaScriptEnabled to false if you render files that are not supposed to run JavaScript.

IOS WebView is a bit of a headache, because iOS 8 has always been a UIWebView, iOS 8 has a new WKWebView, so iOS 9.3 300ms delay BUG fix exactly what to do, with the help of the client iOS little sister. The final test result is that UIWebView has a 300ms latency problem that persists even on the latest iOS versions. However, WKWebView fixed this issue in iOS 9.3, which means that WKWebView still had 300ms delay before iOS 9.3 (after a long time, we finally sorted out all the problems 🙄).

FastClick principle analysis

This part may have a bit rotten avenue, one search on the net a big, say again also have no what meaning, I pick point individual feel interesting say 😁

The principle of

First, let’s talk about how fastClick is implemented. MDN also supports both touch screen events and mouse events.

On the mobile side, when the user clicks the screen, touchStart, TouchMove (0 or more times), TouchEnd, Mousemove, MouseDown, mouseup, and Click will be triggered in sequence. Touchmove. The TouchMove event is triggered only when the finger moves on the screen. The Event. preventDefault, Mouse and Click events will not fire if either of the TouchStart, TouchMove or TouchEnd events is called

FastClick calls Event.preventDefault in the TouchEnd phase and creates a MouseEvents with Document.createEvent, And then through the eventTarget. DispatchEvent trigger the corresponding target element binding on the click event

You don’t knowJavaScript (Maybe)

First of all, we need to clarify a problem. The 300ms delay is only available on mobile, not PC. A notNeeded function in fastClick is used to determine whether fastClick is needed. In the beginning, I read the code to express my dissatisfaction with the lack of a distinction between mobile and PC. But then a small piece of code changed my mind

// Devices that don't support touch don't need FastClick
if (typeof window.ontouchstart === 'undefined') {
  return true;
}
Copy the code

There is no touch event on PC, so window. onTouchStart returns undefined, and null if there is no binding event on mobile. As expected can only prove that I am still too young 🤣

While reading the source code, I came across a bug in the mobile version of Safari using event delegates when click events are not bound to interactive elements (such as HTML divs) and there are no direct event listeners bound to them. The Click event is not emitted. See Click browser compatibility for details

The solution is as follows :(please forgive me for brazenly moving directly to 😝)

  • For its element or its ancestor element, addcursor: pointerStyle to make the element interactive clickable
  • Add for elements that require interactive clickingonclick="void(0)"Property, but not the body element
  • Use clickable elements such as<a>, instead of non-interactive elements such as div
  • Do not use click’s event delegate.

Event. stopPropagation will only prevent the propagation of events of the same type (event. Type is the same). If I call Event. stopPropagation in TouchStart, it will only block subsequent TouchStart events on event flow, not TouchMove. The occurrence of mouseEvent such as Touchend

Event. StopPropagation event. StopImmediatePropagation you really know the difference between a 🧐, event. StopPropagation stop capture and further spread of the current events in the bubbling phase. If there are multiple event listeners of the same type of event bound to the same element, when events of that type are fired, they are executed in the order in which they were added. If one of monitoring function performs the event. StopImmediatePropagation method, then the rest of the current element to monitor function will not be executed

EventTarget. DispatchEvent will trigger a complete event flow, rather than just registered event trigger eventTarget itself

In general, the process of reading source code is a process of self-cultivation, is the perfection of some deficiencies in the past, in fact, is to find themselves very dish 😂, the road ahead is dangerous and long, comrades still need to work hard 🤜

insufficient

Personally feel that reading excellent source code is a very happy thing, because it can imperceptibly enhance your aesthetic ability. But at the same time we also want to have a critical eye, find out where there are shortcomings

In general, the notNeeded function in fastClick is pretty good, but the downside is that the introduction of fastClick is unnecessary and potentially problematic for those who use WKWebView on iOS 9.3 and above. As a Virgo, this is intolerable. But you can’t distinguish UIWebView from WKWebView simply by UA. However, if the page is in your App, you can carry the WebView information in the UA to decide whether to load or not

Delay detection code


      
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style></style>
  </head>
  <body>
    <div>
      <label for="userAgent">userAgent:</label>
      <span id="userAgent"></span>
    </div>
    <div>
      <label for="touchstart">touchstart:</label>
      <span id="touchstart"></span>
    </div>
    <div>
      <label for="touchend">touchend:</label>
      <span id="touchend"></span>
    </div>
    <div>
      <label for="click">click:</label>
      <span id="click"></span>
    </div>
    <div>
      <label for="diffClickTouchend">diff click - touchend:</label>
      <span id="diffClickTouchend"></span>
    </div>
    <div>
      <div id="test">test</div>
      <div id="diff">diff</div>
    </div>
    <script>
      var userAgent = document.getElementById('userAgent');
      userAgent.innerText = window.navigator.userAgent;

      var test = document.getElementById('test');
      var diff = document.getElementById('diff');
      var touchstart = document.getElementById('touchstart');
      var touchend = document.getElementById('touchend');
      var click = document.getElementById('click');
      var diffClickTouchend = document.getElementById('diffClickTouchend');

      test.addEventListener('touchstart'.function(e) {
        touchstart.innerText = Date.now();
      });

      test.addEventListener('touchend'.function(e) {
        touchend.innerText = Date.now();
      });

      test.addEventListener('click'.function(e) {
        click.innerText = Date.now();
      });

      diff.addEventListener('click'.function() {
        diffClickTouchend.innerText = click.innerText - touchend.innerText;
      });
    </script>
  </body>
</html>
Copy the code

conclusion

Looking back at history, there is no denying that fastClick has made a great contribution to solving the 300ms latency problem on mobile, but is it still necessary to use 9102 today? Going back to the beginning, I said that what fits you is best, so if your business needs, You only need to adapt WKWebView for iOS 9.3 or above, so you are strongly advised not to use it, after all, it reduces the size of file request and introduces the probability of risk. Finally, to quote the famous old soldier never dies, just fades in homage to fastClick.

Reference (References)

  • What Exactly Is….. The 300ms Click Delay
  • 300ms tap delay, gone away
  • How to design an elegant and robust Android WebView?
  • UIWebView
  • Both touch screen events and mouse events are supported
  • Click browser Compatibility