Calling system functions

< A > can quickly call the three communication functions of mobile devices, such as telephone, SMS and email, and can quickly call the gallery/file of mobile devices.

These functions facilitate the interaction between the page and the system. The key is that the call format must be accurate, otherwise it will be ignored by the mobile browser.

<! - call - > < a href = "tel: 10086" > call to 10086 little sister < / a > <! - send SMS - > < a href = "SMS: 10086" > send text messages to 10086 little sister < / a > <! <a href="mailto:[email protected]"> </a> <! - choose the pictures or take photographs - > < input type = "file" accept = "image / *" > <! - select the video or shoot video - > < input type = "file" accept = "video / *" > <! <input type="file" multiple>Copy the code

Ignore automatic identification

Some mobile browsers automatically recognize alphanumeric symbols as phone/email and render them as in the “Call system function” above. It’s convenient but it can be against your needs.

<! <meta name="format-detection" content="telephone=no"> <! <meta name="format-detection" content="email=no"> <! <meta name="format-detection" content="telephone=no, email=no">Copy the code

Pop-up numeric keypad

Use to press the numeric keypad with # and *, suitable for typing phone calls. is recommended to play the numeric keypad. It is suitable for entering pure numeric formats such as verification codes.

<! <input type="tel"> <! <input type="number" pattern="\d*">Copy the code

Wake up native apps

The communication channel between the page and the client is established through location.href, which is called “URL Scheme”. The basic format is Scheme ://[path][? Query]. The author once published the communication Mode between H5 and App to describe the use of URL Scheme.

  • Scheme: indicates the unique identifier of an application in the system
  • Path: indicates the application behavior, indicating that a page or function is applied
  • Query: indicates the application parameter, which indicates the condition parameters required by the application page or application function

Generally, A URL Scheme is negotiated by the front-end and the client. The prerequisite to wake up native apps is that the app must be installed on mobile devices. Some mobile browsers cannot wake up native apps even if the app is installed, because they consider URL Scheme a potentially dangerous behavior and disable it, such as Safari and wechat browsers. Fortunately, wechat browser can enable whitelist to make URL Scheme valid.

If the URL Schema of a third-party native application is referenced on the page, you can capture the URL of the third-party native application.

<!-- 打开微信 -->
<a href="weixin://">打开微信</a>

<!-- 打开支付宝 -->
<a href="alipays://">打开支付宝</a>

<!-- 打开支付宝的扫一扫 -->
<a href="alipays://platformapi/startapp?saId=10000007">打开支付宝的扫一扫</a>

<!-- 打开支付宝的蚂蚁森林 -->
<a href="alipays://platformapi/startapp?appId=60000002">打开支付宝的蚂蚁森林</a>
Copy the code

Disable page zooming

With the popularity of smartphones, many websites offer both desktop and mobile versions of browsing, so there is no need to double click to zoom in and out of the page. Disabling page zooming ensures that mobile browsers can display all page layouts without missing a page.

<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, minimum-scale=1, maximum-scale=1">
Copy the code

Disable page caching

Cache-control specifies the caching mechanism for requests and responses. Disable this if you don’t want to use browser caching.

<meta http-equiv="Cache-Control" content="no-cache">
Copy the code

Prohibit capitalization

Sometimes when you enter text in the input field, the default uppercase correction will be enabled, that is, the input lowercase letter will be automatically corrected to uppercase. Directly declare autocapitalize=off and autocorrect=off.

<input autocapitalize="off" autocorrect="off">
Copy the code

Safari Configuration

Post some of Safari’s more fragmented and rarely used configurations.

<! <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes"> -- Change Safari always, optional default/black/ black-always, <meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <link rel="apple-touch-startup-image" href="pig.jpg" media="(device-width: 375px)"> <! <link rel="apple-touch-icon" sizes="76x76" href="pig.jpg"> <! <link rel="apple-touch-icon-precomposed" href="pig.jpg">Copy the code

For other browser configurations

Post some scattered and less used configuration of other browsers, mainly commonly used QQ browser, UC browser and 360 browser. According to MTL’s test data, the new QQ browser and UC browser do not support the following statement.

<! <meta name="x5-orientation" content="portrait"> <! <meta name="x5-fullscreen" content="true"> <! <meta name="x5-page-mode" content="app"> <! <meta name="screen-orientation" content="portrait"> <! <meta name="full-screen" content="yes"> <! <meta name=" browserMode "content="application"> <! <meta name="renderer" content="webkit">Copy the code

Let :active work, let :hover not work

For some elements, the :active element may be disabled, while the :hover element remains in the clicked state after being clicked, requiring another click to remove the clicked state. Registering an empty TouchStart event to reverses both states.

<body ontouchstart></body>
Copy the code

Monitor screen rotation

Are you still using JS to judge landscape and portrait adjustments? That’s really Out.

/* @media All and (orientation: portrait) {/* custom style */} /* @media all and (orientation: portrait) Landscape) {/* Custom style */}Copy the code

Support for elastic rolling

Scrolling with non-< body> elements can stall on Apple, but not on Android. Optimize elastic scrolling by declaring overflow-scrolling:touch and calling system native scrolling events to increase scrolling fluency.

body {
    -webkit-overflow-scrolling: touch;
}
.elem {
    overflow: auto;
}
Copy the code

Forbid rolling propagation

Unlike desktop browsers, mobile browsers have a strange behavior. When the page contains multiple rolling areas, if there is still rolling momentum after rolling a region, the remaining momentum will be transmitted to the next rolling area, causing the region to also roll. This behavior is called “rolling propagation.”

You can ban it if you don’t want it to happen.

.elem {
    overscroll-behavior: contain;
}
Copy the code

Disable screen jitter

For some pages with sudden appearance of scroll bars, there may be adverse effects of left and right jitter. In a scroll container, open the popover to hide the scroll bar, close the popover to show the scroll bar, and move back and forth to make the screen shake. Declaring the padding-right of the scroll container to be the width of the scroll bar can eliminate this effect.

The width of the scroll bar may vary from mobile browser to mobile browser and may not even occupy the same position. You can calculate the width of the scroll bar indirectly by using the following method. 100vw is the window width, 100% is the scroll container content width, subtract is the scroll bar width, no problem dynamic calculation.

body {
    padding-right: calc(100vw - 100%);
}
Copy the code

Do not long press

Sometimes you do not want users to click the link, make a call, send an email, save a picture or scan the QR code by pressing the element call menu.

Sometimes you don’t want users to copy and paste stolen copy. Declare user-select: None to prevent users from holding down and selecting copy.

* { /* pointer-events: none; */ user-select: none; /* Disable long press to select text */ -webkit-touch-callout: none; }Copy the code

But declaring user-select: None makes and

input,
textarea {
    user-select: auto;
}
Copy the code

Prohibit font adjustment

While rotating the screen may change the font size, declare text-size-adjust:100% to leave the font size unchanged.

* {
    text-size-adjust: 100%;
}
Copy the code

Disable highlighting touch elements that appear translucent grey masks, do not want!

* {
    -webkit-tap-highlight-color: transparent;
}
Copy the code

Disable animated flash screen

When adding an animation to a mobile device, most of the time a flash screen will appear. Creating a 3D environment for the parent element of the animation element will keep the animation stable.

.elem {
    perspective: 1000;
    backface-visibility: hidden;
    transform-style: preserve-3d;
}
Copy the code

Make forms look good

Appearance: None to help you customize the form element style.

button, input, select, textarea { appearance: none; /* Custom style */}Copy the code

Beautify scrolling placeholders

The scrollbar style is too ugly to want to customize, ::-webkit-scrollbar-* to help you. Remember the following three key words to be flexible.

  • ::-webkit-scrollbar: indicates the entire part of the scrollbar
  • ::-webkit-scrollbar-track: indicates the track part of the scrollbar
  • ::-webkit-scrollbar-thumb: part of the scrollbar slider
::-webkit-scrollbar {
    width: 6px;
    height: 6px;
    background-color: transparent;
}
::-webkit-scrollbar-track {
    background-color: transparent;
}
::-webkit-scrollbar-thumb {
    border-radius: 3px;
    background-image: linear-gradient(135deg, #09f, #3c9);
}
Copy the code

Beautify the input placeholder

Input box placeholder text is too ugly, ::-webkit-input-placeholder to help you.

input::-webkit-input-placeholder {
    color: #66f;
}
Copy the code

Align input placeholders

Students with obsessive-compulsive disorder always feel that the text position of the input box is on the whole, and the feeling is not centered. In the desktop browser, declare line-height equal to height. In the mobile browser, declare line-height equal to height.

input {
    line-height: normal;
}
Copy the code

Align the drop-down options

The dropdown options are aligned to the left by default, so it’s time to align them to the right.

select option {
    direction: rtl;
}
Copy the code

Fixed invalid click

On Apple systems, there are cases where listening for click events on non-clickable elements may not be effective; this can be solved by declaring cursor:pointer on elements that do not trigger click events.

.elem {
    cursor: pointer;
}
Copy the code

Recognize text newlines

Most of the time you’ll use JS newline text, and that’s really Out. If the interface return field contains \n or

, do not replace it. Instead, declare white-space:pre-line and submit it to the browser for line breaking.

* {
    white-space: pre-line;
}
Copy the code

Enabling Hardware Acceleration

If you want to animate more smoothly, turn on GPU hardware acceleration!

.elem {
    transform: translate3d(0, 0, 0);
    /* transform: translateZ(0); */
}
Copy the code

Draw pixel borders

Ten thousand years topic, how to depict a pixel border?

.elem { position: relative; width: 200px; height: 80px; &::after { position: absolute; left: 0; top: 0; border: 1px solid #f66; width: 200%; height: 200%; content: ""; transform: scale(.5); transform-origin: left top; }}Copy the code

Control overflow text

Ten thousand years topic, how to control text to do single line overflow and multi-line overflow?

.elem { width: 400px; line-height: 30px; font-size: 20px; &.sl-ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } &.ml-ellipsis { display: -webkit-box; overflow: hidden; text-overflow: ellipsis; -webkit-line-clamp: 3; -webkit-box-orient: vertical; }}Copy the code

Disable click penetration

It is well known that there will be 300ms delay in click operation in mobile browser, which often causes click delay and even invalid click.

Safari, the first iPhone released by Apple in 2007, uses double-click zooming to make desktop web sites look good on mobile browsers. This scheme is the main reason for the 300ms delay. After the user clicks for the first time, 300ms will be reserved to check whether the user clicks again. If the user clicks again, the zoom operation will be performed. Given its success, the solution has been copied by other mobile browsers and is now available in almost all mobile browsers. The click delay caused by this scheme is called “click penetration”.

The first solution to clickthrough in the front-end domain was Zepto in the era of jQuery. It is estimated that most of you have never used Zepto. In fact, it is the mobile version of jQuery. Zepto encapsulates tap events to effectively solve tap penetration by listening to touch events on document to complete the simulation of TAP events and bubbling tap events onto document to trigger.

Use touch events instead of click events on mobile browsers because click events have significant latency, followed by FastClick. The solution listens for whether the user has made a double click, normally using the Click event, and fastClick automatically determines if the click has passed. More fastClick principle can be self-baidu, in this not too much introduction.

Fastclick has a ready-made NPM package that can be installed directly into your project. Fastclick allows you to use click events instead of tap events in a very simple way.

import Fastclick from "fastclick";

FastClick.attach(document.body);
Copy the code

No sliding penetration

It’s a well-known fact that when pop-ups appear in mobile browsers, swiping on the screen triggers the content underneath to scroll along.

The first step is to clarify what interaction needs to be maintained by sliding through. That is, nothing can be clicked or scrolled except popover content. Many current solutions fail to do this, and rolling behavior, which all solutions prohibit, causes other problems.

  • Internal contents cannot scroll after popover opens
  • The scrolling position of the page is lost after the popover is closed
  • The Webview can slide up and down to reveal the background color

Declare position:fixed; left:0; Width :100% and dynamically declare top. Declaring position: Fixed causes the scroll bar to disappear. In this case, you will find that although there is no slide penetration, the page scroll position has been lost. Get the current scroll bar offset of the page by scrollingElement, take it negative and assign it to TOP, and there is no visual change. Remove position:fixed while closing popover; left:0; Width :100% and dynamic top.

ScrollingElement is compatible with properties such as scrollTop and scrollHeight, and works well in mobile browsers. Document. ScrollingElement. ScrollHeight can perfect instead of once the document. The documentElement. ScrollHeight | | document. Body. ScrollHeight, At first glance, it looks like less code.

This solution has no visual change, and is better than any other solution. It is a reverse thinking and a smoke screen. This solution perfectly solves the impact of fixed popovers and scroll popovers on the global scroll. Of course, it can also be used in local scroll containers, so it is worth promoting.

body.static {
    position: fixed;
    left: 0;
    width: 100%;
}
const body = document.body;
const openBtn = document.getElementById("open-btn");
const closeBtn = document.getElementById("close-btn");
openBtn.addEventListener("click", e => {
    e.stopPropagation();
    const scrollTop = document.scrollingElement.scrollTop;
    body.classList.add("static");
    body.style.top = `-${scrollTop}px`;
});
closeBtn.addEventListener("click", e => {
    e.stopPropagation();
    body.classList.remove("static");
    body.style.top = "";
});
Copy the code

Round-trip refresh support

Clicking the forward or back buttons of the mobile browser sometimes does not automatically execute the JS code of the old page, due to round-trip caching. This is especially true in Safari, where the round-trip page cannot be refreshed.

Round-trip caching (BFCache) is a strategy used by browsers to move forward and backward between pages in a smoother experience. The strategy is as follows: when the user goes to the new page, the DOM state of the old page is saved in BFCache; when the user returns to the old page, the DOM state of the old page is removed from BFCache and loaded. Most mobile browsers deploy BFCache, which greatly reduces the time and bandwidth of interface requests.

The solution to what BFCache is can be found at Window. onunload.

// Listen for the page destruction event window.addEventListener("onunload", () => {// execute old page code});Copy the code

If using keep-alive on Vue SPA does not refresh the page, place the interface request in beforeRouteEnter().

There is, of course, another solution. The PagesHow event fires every time a page loads, whether it is the first time it is loaded or the next time it is loaded, which is what distinguishes it from the Load event. The PagesHow event exposes persisted to determine whether the page is persisted from BFCache.

window.addEventListener("pageshow", e => e.persisted && location.reload());
Copy the code

If the browser does not disable caching with
, this solution is still worth using.

Analytic date of validity

On apple systems, the Date format YYYY-MM-DD HH: MM :ss returns an Invalid Date error, but on Android systems, the Date format has no problem.

new Date("2019-03-31 21:30:00"); // Invalid Date
Copy the code

The date format YYYY/MM/DD HH: MM :ss is available in the Safari development manual. Of course, Android supports this format, but the date format of the interface return field is usually YYYY-MM-DD HH: MM :ss, so replace the – with /.

const date = "2019-03-31 21:30:00";
new Date(date.replace(/\-/g, "/"));
Copy the code

Repair height collapse

When the following three conditions are present on the page at the same time, the keyboard placeholder will compress a portion of the page. When the keyboard placeholder disappears after the input is completed, the page height may not return to the original height, resulting in collapse and resulting in the appearance of the background color of the Webview. A simple summary is that the page does not rebound after the input box is out of focus.

  • The page height is too small. Procedure
  • The input box is at the bottom of the page or at the bottom of the window
  • Input fields focus on input text

This problem does not occur as long as the offset of the front and back scroll bars is the same. The current scroll bar offset of the page is obtained when the input box is focused, and the scroll bar offset obtained before the page is assigned when the input box is out of focus. In this way, the scroll bar offset of the page can be indirectly restored to solve the height collapse of the page.

const input = document.getElementById("input");
let scrollTop = 0;
input.addEventListener("focus", () => {
    scrollTop = document.scrollingElement.scrollTop;
});
input.addEventListener("blur", () => {
    document.scrollingElement.scrollTo(0, this.scrollTop);
});
Copy the code

Fix input listening

The keyUP/KeyDown/keyPress event may be invalid if you enter text in the input box on the MAC. When the input box listens for the keyUP event, typing English and digits one by one is effective, but typing Chinese characters one by one is not effective. You need to press Enter to make the event effective.

In this case, input events can be used instead of keyUP/KeyDown/keyPress events in the input box.

Simplify back to the top

There was a time when writing a function that returned to the top was a pain in the neck, requiring a combination of scrollTop, timer, and conditional judgment. There’s a nice function hidden in the DOM object that does all this in a single line of core code.

This function, called scrollIntoView, scrolls the parent container of the target element to make it visible to the user. In short, it scrolls the container to the target element relative to the window. It has three optional arguments to make scrollIntoView scroll more gracefully.

  • Behavior: Animation transition effect. The default value is AUTO. The option is smooth
  • “Inline” : horizontal alignment with nearest alignment by default, top alignment of start, center alignment and bottom alignment of end are optional
  • “Block” : vertical alignment, default alignment at top of START, optional alignment at center, bottom of End and nearest
const gotopBtn = document.getElementById("gotop-btn");
openBtn.addEventListener("click", () => document.body.scrollIntoView({ behavior: "smooth" }));
Copy the code

You can also scroll to the target element by changing document.body to the DOM object of the target element. Isn’t it tiring to write so much code when you can do it with one line of core code?

Simplify lazy loading

As with simplicity back to top, writing a lazy loading function also requires a combination of scrollTop, timer, and conditional judgment. In fact, there is a very useful function hidden in the DOM object to accomplish the above function. This function does not need to listen for the container’s Scroll event, through the browser’s own mechanism to complete the scroll listening.

This function, IntersectionObserver, provides a way to asynchronously observe the intersecting state of the target element and its ancestor or top-level document window. Refer to the MDN documentation for more details, which will not be covered here.

The first use case for lazy loading is “image lazy loading”. Just make sure the image is in the viewable area and assign to load the image. Once the assignment is complete, stop listening for the image.

<img data-src="pig.jpg">
Copy the code
<! - a lot of the < img > -- > const imgs = document. QuerySelectorAll (" img. The lazyload "); Const Observer = new IntersectionObserver(Nodes => {nodes.forEach(v => {if (v.isintersecting) {// Determines whether to enter the visible area v.target.src = v.target.dataset.src; // Assign to observer.unobserve(v.target); // Stop listening for loaded images}}); }); imgs.forEach(v => observer.observe(v));Copy the code

The second use scenario for lazy loading is “pull-down loading.” Deploy a placeholder element at the bottom of the list without any height or physical appearance and ask the interface to load the data simply by confirming that the placeholder element is in the viewable area.

<ul> <li></li> <! -- many <li> --> </ul> <! <div id="bottom"></div>Copy the code
const bottom = document.getElementById("bottom"); const observer = new IntersectionObserver(nodes => { const tgt = nodes[0]; If (tgt.isintersecting) {console.log(" bottom, request interface "); }}) bottom.observe(bottom);Copy the code

Optimized scan recognition

Usually mobile browsers are equipped with the function of long pressing the TWO-DIMENSIONAL code image to identify links, but long pressing the two-dimensional code may not be recognized or misrecognized. Two-dimensional code surface looks like a picture, but two-dimensional code generation is multifarious, two-dimensional code generation has the following three kinds.

  • [x]use<img>Apply colours to a drawing
  • [x]use<svg>Apply colours to a drawing
  • [x]use<canvas>Apply colours to a drawing

According to MTL’s test data, most mobile browsers can only recognize the QR code rendered by < IMG >. In order for all mobile browsers to recognize the QR code, the qr code rendered by < IMG > can only be used. If you use SVG and Canvas to generate the TWO-DIMENSIONAL code, then try to convert the two-dimensional code data into Base64 and assign the value to SRC.

There may be multiple two-dimensional codes on a page, if long press the two-dimensional code can only identify the last one, it can only control the existence of only one two-dimensional code on each page.

Autoplay media

Common media elements include audio

const audio = document.getElementById("audio");
const video = document.getElementById("video");
audio.play();
video.play();
Copy the code

For built-in browsers like wechat browser, the above code can be triggered only after the application SDK is loaded to ensure the normal rendering of WebView. The same goes for other built-in browsers, which I won’t cover too much here.

Document. The addEventListener (" WeixinJSBridgeReady ", () = > {/ / code executed automatically play the media});Copy the code

The Apple system clearly stipulates that media can be played only after user interaction starts. If there is no response from the user, The media will be automatically blocked by Safari. Therefore, the listener needs to listen for the user’s first touch and trigger the media to play automatically.

Document. The body. The addEventListener (touchstart, () = > {/ / code executed automatically play the media}, {once: true});Copy the code