☞ Mobile end adaptation and PC end adaptation experience (a) (may be more complete

Problems with Web adaptation

1. The browser mate specifies the kernel

QQ browser meta element detection and identification kernel rules

Identified as the Chrome kernel
  • Doctype for the standard
  • Meta tag element

Example:

<! DOCTYPEhtml>
<html>
  <head>
    <! -- Select one of the following meta to correctly identify -->
    <meta name="renderer" content="webkit" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta http-equiv="X-UA-Compatible" content="chrome=1" />
    <title>chrome core</title>
  </head>
  <body>
  meta webkit
  </body>
</html>
Copy the code
Identifies as an IE kernel
  • Doctype is non-standard
  • Meta Element detection

Example:

<! DOCTYPEhtml PUBLIC "- / / / / W3C DTD XHTML 1.0 Transitional / / EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
  <head>
    <! -- Select one of the following meta to correctly identify -->
    <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
    <meta name="renderer" content="ie-comp" />
    <meta name="renderer" content="ie-stand" />
    <title>ie core</title>
  </head>
  <body>
  meta ie
  </body>
</html>
Copy the code

Reference: QQ browser document

2. 1px borders

Causes of occurrence:

According to the size of iPhone6, a 750px wide design drawing is actually the device pixel of iPhone6. The 1px measured in the design drawing is actually 1 device pixel. When we set the layout viewport equal to the ideal viewport equal to 375px, and since the DPR of iPhone6 is 2, When writing CSS, 1px corresponds to 2 device pixels, so it will look thicker.

The solution

1.border-image

Judge different device pixel ratio based on media query given different border-image:

.border_1px{
          border-bottom: 1px solid # 000;
        }
        @media only screen and (-webkit-min-device-pixel-ratio:2) {.border_1px{
                border-bottom: none;
                border-width: 0 0 1px 0;
                border-image: url(../img/1pxline.png) 0 0 2 0stretch; }}Copy the code
2. background-image

Similar to the border-image, prepare a qualified border background image and simulate it on the background.

.border_1px{
          border-bottom: 1px solid # 000;
        }
@media only screen and (-webkit-min-device-pixel-ratio:2{
.border_1px{
        background: url(../img/1pxline.png) repeat-x left bottom;
        background-size: 100% 1px; }}Copy the code

Both require separate images, and rounded corners are not easy to handle, but will work for most scenes.

3. Pseudo-class + transform

Determine the pixel ratio of different devices based on media query to scale the line:

.border_1px:before{
          content: ' ';
          position: absolute;
          top: 0;
          height: 1px;
          width: 100%;
          background-color: # 000;
          transform-origin: 50% 0%;
        }
        @media only screen and (-webkit-min-device-pixel-ratio:2) {.border_1px:before{
                transform: scaleY(0.5); }}@media only screen and (-webkit-min-device-pixel-ratio:3) {.border_1px:before{
                transform: scaleY(0.33); }}Copy the code

This method can be used for various scenarios. If rounded corners are needed, just add border-radius to the pseudo-class.

4. Use SVG (plug-in helppostcss-write-svg)

The above border-image and background-image can simulate 1px borders, but they are bitmaps and need to be imported externally.

With postCSs-write-svg we can create a 1px border for SVG directly using border-image and background-image:

@svg border_1px { 
  height: 2px; 
  @rect { 
    fill: var(--color, black); 
    width: 100%; 
    height: 50%; }}.example { border: 1px solid transparent; border-image: svg(border_1px param(--color #00b1ff)) 2 2 stretch; }
Copy the code

The compiled:

.example { border: 1px solid transparent; border-image: url("data:image/svg+xml; charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='2px'%3E%3Crect fill='%2300b1ff' width='100%25' height='50%25'/%3E%3C/svg%3E") 2 2 stretch; }
Copy the code

3. The adapter iPhoneX

We need to properly place the top and bottom within the security zone. In iOS11, two new CSS functions, env and constant, are used to set the distance between the security zone and the boundary.

There can be four constants inside a function:

  • safe-area-inset-left: Distance between the security zone and the left boundary
  • safe-area-inset-right: Distance between the security zone and the right boundary
  • safe-area-inset-top: Distance between the security zone and the top boundary
  • safe-area-inset-bottom: Distance between the security zone and the bottom boundary

Note: We must specify viweport-fit to use these two functions:

<meta name="viewport" content="width=device-width, viewport-fit=cover">
Copy the code

Constant works on iOS < 11.2, env works on iOS >= 11.2, which means we tend to set them both, limiting pages to safe zones:

body {
  padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom);
}
Copy the code

When using the bottom fixed navigation bar, we need to set the padding value for them:

{
  padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom);
}
Copy the code

Specific details

Aotu. IO/notes / 2017 /…

4. Landscape

Js recognition

window.addEventListener("resize".() = >{
    if (window.orientation === 180 || window.orientation === 0) { 
      // Rotate the screen 180 degrees in normal direction
        console.log('portrait');
    };
    if (window.orientation === 90 || window.orientation === -90) {// The screen rotates 90 degrees clockwise or 90 degrees counterclockwise
        console.log('landscape'); }});Copy the code

The CSS to identify

@media screen and (orientation: portrait) {
  / * vertical screen... * /
} 
@media screen and (orientation: landscape) {
  / * landscape... * /
}
Copy the code

5. Blurred pictures

1 Causes

Most of the images we use are bitmaps (PNG, JPG..) A bitmap is made up of individual pixels, each with a specific position and color value:

In theory, each pixel of the bitmap should be rendered using one physical pixel on the screen for optimal display.

On a screen with DPR > 1, a pixel of the bitmap may be rendered by multiple physical pixels. However, these physical pixels cannot be accurately assigned to the color of the corresponding bitmap pixel, and can only be approximated, so the same image will be blurred on a screen with DPR > 1:

2 Solution

In order to ensure image quality, we should render one image pixel with one screen pixel as much as possible, so we need to display images with different resolutions for different DPR screens.

For example, display a double graph (@2x) on a screen with DPR =2 and a triple graph (@3x) on a screen with DPR =3.

3 media query

Use media query to judge the pixel ratio of different devices to display pictures with different precision:

.avatar{
            background-image: url(conardLi_1x.png);
        }
        @media only screen and (-webkit-min-device-pixel-ratio:2) {.avatar{
                background-image: url(conardLi_2x.png); }}@media only screen and (-webkit-min-device-pixel-ratio:3) {.avatar{
                background-image: url(conardLi_3x.png); }}Copy the code

Only for background images

4 image-set

Use the image – set:

.avatar {
    background-image: -webkit-image-set( "conardLi_1x.png" 1x, "conardLi_2x.png" 2x );
}
Copy the code

Only for background images

5 srcset

Using the srcset attribute of the IMG tag, the browser automatically matches the best display image based on pixel density:

<img src="conardLi_1x.png"
     srcset=" conardLi_2x.png 2x, conardLi_3x.png 3x">
Copy the code
6 JavaScript Splicing image URL

Use window.devicePixelRatio to get the devicePixelRatio, traverse all the images, and replace the image address:

const dpr = window.devicePixelRatio;
const images =  document.querySelectorAll('img');
images.forEach((img) = >{
  img.src.replace(".".` @${dpr}x.`);
})
Copy the code
7 using SVG

SVG stands for scalable vector graphics. Unlike bitmaps, which are pixel-based, SVG is a shape description of an image, so it is essentially a text file, small in size and undistorted no matter how many times it is magnified.

In addition to drawing SVG manually in code, we can also use SVG images as bitmaps:

<img src="conardLi.svg">
<img src="data:image/svg+xml; base64,[data]">
.avatar {
  background: url(conardLi.svg);
}
Copy the code

Reference:

Mobile adaptation

Headlines mobile adaptation

H5 related

What is the h5

H5 technology is a set of mobile web front-end technologies

The H5 technology itself is the Web page for mobile. As the App itself has a webView container, in which Web front-end codes can be run, Hybrid App technology is derived from the combination of H5 and native App.

General principles of Hybrid App technology

Mobile responsive layout

Solution 1: REM + pxToRem

The principle of
  1. Monitor the width of the screen window, assigned by a proportional conversion tohtmlthefont-size. At this point, the root font size varies with the screen width.
  2. willpxConverted toremThere are two kinds of conventional programs. One is to usesass/lessCustom function inpxToRemWrite,pxThe use ofpxToRemFunction conversion torem. The other way is to just write itpx, the compilation process uses plug-ins to convert allrem. suchdomThe size of the element in the screen will change with the screen width.
implementation
  1. Dynamically update the root font size
const MAX_FONT_SIZE = 420
// Define the maximum screen width
document.addEventListener('DOMContentLoaded'.() = > {
  const html = document.querySelector('html')
  let fontSize = window.innerWidth / 10
  fontSize = fontSize > MAX_FONT_SIZE ? MAX_FONT_SIZE : fontSize
  html.style.fontSize = fontSize + 'px'
})

Copy the code
  1. pxrem
pxToRemPlan a
$rootFontSize: 375 / 10; // Define the function where px is converted to rem@function px2rem ($px) {
    @return $px / $rootFontSize + rem;
}
.demo {
    width: px2rem(100);
    height: px2rem(100);
}
Copy the code
pxToRemScheme 2

Install the PostCSS-Pxtorem plugin in VuE-CLI3. Other platforms have similar ideas.

const autoprefixer = require('autoprefixer')
const pxtorem = require('postcss-pxtorem')
module.exports = { 
  // ...
  css: {
    sourceMap: true.loaderOptions: {
      postcss: {
        plugins: [
          autoprefixer(),
          pxtorem({
            rootValue: 37.5.propList: [The '*']})]}}}}Copy the code

Continue to explore postCSS-PxtoREM plug-in source code, see how it is implemented.

function createPxReplace (rootValue, unitPrecision, minPixelValue) {
    return function (m, $1) {
        if(! $1) return m;
        var pixels = parseFloat($1);
        if (pixels < minPixelValue) return m;
        var fixedVal = toFixed((pixels / rootValue), unitPrecision);
        return (fixedVal === 0)?'0' : fixedVal + 'rem';
    };
}
Copy the code

The transformation of PX into REM is mainly this function, of course, there are a lot of configurable parameters, the core principle is similar to our plan 1. The convenience is that you don’t have to add a function every time you write px, and the code is much cleaner.

Should all elements px be converted to REM? That’s not true, px should not be converted to REM in the border, which is another 1px problem, as discussed in the previous article. Avoid converting PX to REM, and capitalize px in the border to PX/ px/px

Solution 2: VH + VW

The principle of

vwA unit of window width that varies with width.

implementation

Similarly, postCSS-pxtoREM is configured using the postCSs-pxto-viewPort plugin. Plug-ins work the same way

Other Solutions

plan defects
1 The percentage Height failure percentage
2 Media Enquiries +metaviewport Different devices have different widths, and the scaling ratio cannot be completely determined
3 flex It still doesn’t solve the width overrun problem

All of the above schemes have fatal defects and are not recommended for mobile terminal layout calculation.

Flex is best used with REM

Vue quickly configures mobile templates

reference

Open source library solutions

1. The vant component library

In the Vant component library, px is used as the measurement unit by default. If rem is needed, the plug-in is perfect for it.

For VW scenarios, Vant can also convert PX to VW through plug-ins, and there may be some pothole points for VW.

2. The ant – design – mobile component library

The Ant-Design-Mobile component library still uses px units

@hd: 1px; // Basic unit // font size // --@font-size-icontext: 10 * @hd;
@font-size-caption-sm: 12 * @hd;
@font-size-base: 14 * @hd;
@font-size-subhead: 15 * @hd;
@font-size-caption: 16 * @hd;
@font-size-heading: 17* @hd; // round corners // --@radius-xs: 2 * @hd;
@radius-sm: 3 * @hd;
@radius-md: 5 * @hd;
@radius-lg: 7 * @hd;
@radius-circle: 50%; // Frame size // --@border-width-sm: 1PX;
@border-width-md: 1PX;
@border-width-lg: 2 * @hd;
Copy the code

Summary of h5 problems

1. Ios doesn’t swipe smoothly

performance

Swiping up and down the page creates a stutter, and when your finger leaves the page, the page immediately stops moving. The overall performance is not smooth sliding, no sliding inertia.

The reasons causing

Why is iOS webView not sliding smoothly, and how is it defined?

In iOS 5.0 and later, there are two values for sliding: auto and touch. The default is auto.

-webkit-overflow-scrolling: touch; /* When the finger is removed from the touch screen, it keeps scrolling for a while */
-webkit-overflow-scrolling: auto; /* When the finger is removed from the touch screen, scrolling stops immediately */
Copy the code

The solution

1. Add the scroll touch method to the scroll container

Set -webkit-overflow-scrolling to touch

.wrapper {
    -webkit-overflow-scrolling: touch;
}
Copy the code

Container ::-webkit-scrollbar {display: none; }

May result in position:fixed; Fixed positioned elements that scroll along with the page

2. Set the overflow

Set the external overflow to Hidden and the content element overflow to Auto. The inner element beyond the body produces a scroll, and the part beyond the body is hidden.

body {
    overflow-y: hidden;
}
.wrapper {
    overflow-y: auto;
}
Copy the code

A combination of the two is better!


2. IOS pull-up boundary pull-down appears white blank

performance

Hold your finger on the screen and pull it down to create a white area at the top of the screen. Hold your finger on the screen and pull, creating a white area at the bottom.

The reasons causing

In iOS, holding a finger and dragging it up and down triggers the TouchMove event. This event triggers the entire WebView container, which will naturally be dragged, leaving the rest blank.

The solution
1. Do not slide listening events

There are three touch events on the mobile terminal, which are defined as

1.touchStart: Place your finger on a DOM element.2.touchMove: Drag a DOM element with your finger.3.touchend: Remove the finger from a DOM element.Copy the code

Obviously what we need to control is the TouchMove event

touchmoveThe speed of events is implementation-definable, depending on hardware performance and other implementation details

preventDefaultMethod to block all default behavior on the same touch, such as scrolling.

Therefore, we found a solution. By listening to TouchMove, we made it possible to slide where it was needed and forbidden to slide where it was not needed.

It is important to note that we filter out elements that have scroll containers.

The implementation is as follows:

document.body.addEventListener('touchmove'.function(e) {
    if(e._isScroller) return;
    // Block the default event
    e.preventDefault();
}, {
    passive: false
});
Copy the code
2. Scroll to compromise to fill in the blanks and decorate into other features

In many cases, we can stop trying to solve this problem and start thinking about it. Depending on the scenario, we can use the drop-down as a functional operation.

For example: refresh the page after the drop-down


3. The page enlarges or reduces the uncertain behavior

performance

Double-click or open the finger page element with both fingers to zoom in or out.

The reasons causing

HTML itself generates zooming in and out behavior, such as in a PC browser, where pages can be zoomed in and out freely. But on mobile, we don’t need this behavior. Therefore, we need to prohibit this uncertain behavior to improve the user experience.

Principles and solutions

The HTML meta meta tag standard has a medium viewPort property that controls the zoom of a page. It is usually used on mobile devices. Described in MDN in the following figure

<meta name="viewport" content="width=device-width.initial-scale=1.0">
Copy the code

So maximum-scale, minimum-scale, and user-scalable=no can be used to avoid this problem

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

Prevents page enlargement (when meta doesn’t work)

  window.addEventListener(
    "touchmove".function (event) {
      if(event.scale ! = =1) { event.preventDefault(); }}, {passive: false});Copy the code

4. Click event delay and penetration

performance

Listen for element click event, click element trigger time delay is about 300ms.

Click on the mask layer, after the mask disappears, the lower element clicks trigger.

The reasons causing
Why is there a click delay?

In safari on iOS, to double – click zoom operation, click 300ms later, if the second click is not performed, click operation. That is, to determine whether the user’s behavior is caused by a double click. However, in the App, a click creates a 300ms delay whether or not you need to double click to zoom.

Why does click penetration occur?

When a two-layer element is stacked, the touch event is bound to the upper element and the click event to the lower element. Since click occurs after touch, clicking on the upper element causes the element to disappear, and the lower element triggers the click event, creating the click-through effect.

Principles and solutions
Solution 1: Replace Click with TouchStart

As mentioned earlier, mobile devices support not only clicks, but also several touch events. So the basic idea here is to use the Touch event instead of the click event.

Replacing click with TouchStart not only solves the click event delay problem, but also solves the penetration problem. Because penetration problems occur when touch and click are mixed.

Used in native

el.addEventListener("touchstart".() = > { console.log("ok"); }, false);
Copy the code

Used in VUE

< button@touchStart ="handleTouchstart()"> click </button>Copy the code

Open source solutions also provide both click and TouchStart events. Such as the Button component in vant

So, is it possible to putclickThe events are all replaced bytouchstart? Why are open source frameworks still givenclickThe event?

We imagine a scene that requires clicking and swiping at the same time. What happens if you replace click with touchStart?

Event trigger sequence: TouchStart, TouchMove, TouchEnd, click.

It’s easy to imagine that when I need to swipe touchMove, the touchStart click event is preferentially triggered. Is there already a conflict?

So, in the case of scrolling, the click handle is recommended.

This is also done in the following FastClick open source library.

The main purpose is to ensure that the click event is not under the scrolling parent when synthesized using TouchStart.

Solution 2: Use the FastClick library

Use NPM or YARN after installation

import FastClick from 'fastclick';
FastClick.attach(document.body, options);
Copy the code

Also, with the Fastclick library, click latency and penetration issues are eliminated

In my general practice, when it comes to open source libraries, it’s important to understand how it works. It is mainly to encapsulate the existing native event set into a strong compatibility event set.

Fastclick source code core code is not long, less than 1000 lines. Have interest can understand!


5. The soft keyboard will top up the page and put it away without falling back

performance

On Android phones, when you click on the Input box, the keyboard pops up and pops up the page, causing the page style to mess up.

When the focus is removed, the keyboard is folded up and the keyboard area is blank without falling back.

The reasons causing

We’re going to have a fixed bottom in our app layout. On some versions of Android, typing in a popup will extract the absolute and fixed elements. Resulting in a smaller viewable area, layout confusion.

Principles and solutions
Plan 1:

Listen for input out of focus events, which fall out of focus

/iphone|ipod|ipad/i.test(navigator.appVersion) &&
  document.addEventListener(
    "blur".(event) = > {
      // execute only when the page does not have a scroll bar, because this problem does not occur when there is a scroll bar
      // The input textarea tag is executed because a tags also trigger blur events
      if (
        document.documentElement.offsetHeight <= document.documentElement.clientHeight &&
        ["input"."textarea"].includes(event.target.localName)
      ) {
        document.body.scrollIntoView(); / / back to the top}},true
  );
Copy the code
Scheme 2:

Soft keyboard will page up the solution, mainly by listening to the page height changes, forced to return to the height before the pop-up.

// The height attribute should be changed to style

// Record the original viewport height
const originalHeight = document.body.clientHeight || document.documentElement.clientHeight;
window.onresize = function(){
  var resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
  if(resizeHeight < originalHeight ){
    // Restore the height of the content area
    // const container = document.getElementById("container")
    Container. Style. height = originalHeight;}}Copy the code

The problem of keyboard not falling back appears in iOS 12+ and wechat 6.7.4+, which is a common Bug in the development of wechat H5.

Compatibility principle, 1. Determine version type 2. Change the scrolling visual area

const isWechat = window.navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i);
if(! isWechat)return;
const wechatVersion = wechatInfo[1];
const version = (navigator.appVersion).match(/OS (\d+)_(\d+)_? (\d+)? /);
 
 // If the device type is iOS 12+ or wechat 6.7.4+, restore the original viewport
if (+wechatVersion.replace(/\./g.' ') > =674 && +version[1] > =12) {
  window.scrollTo(0.Math.max(document.body.clientHeight, document.documentElement.clientHeight)); } Duplicate codeCopy the code

Window.scrollto (x-coord, y-coord), where window.scrollto (0, clientHeight) restores to the original viewport


6. IPhone X series security zone adaptation problem

performance

On both sides of the bangs or at the bottom of the head, bangs block the text, or blank areas with black or white background.

The reasons causing

The iPhone X and its successors all feature bangs and gestures across the screen. The head, bottom and sides all need special treatment. In order to adapt to the special circumstances of iPhone X.

The solution

Set security zones and fill dangerous zones. Do not perform operations or display contents in dangerous zones.

Danger area Finger irregularity area, bottom bar area, left and right trigger area.

The specific operation is viewport-fit,meta tag is set to cover, and all regions are filled. Determine whether the device belongs to iPhone X and add an adaptive layer to the bottom of the head

Viewport-fit has three values:

  • auto: This value does not affect the initial layout view port and the entire Web page is viewable.
  • contain: The view port is scaled to fit the display of the largest rectangle embedded.
  • cover: View ports are scaled to populate the device display. Highly recommended usesafe area insetVariable to ensure that important content does not appear outside the display.

Set the viewport – fit tocover

<meta name="viewport" content="width=device-width.initial-scale=1.0, user-scalable=yes, viewport-fit=cover">
Copy the code

Add an adaptive layer

Use the Safe Area inset variable

/* Fit iPhone X top fill */
@supports (top: env(safe-area-inset-top)){
  body..header{
      padding-top: constant(safe-area-inset-top, 40px);
      padding-top: env(safe-area-inset-top, 40px);
      padding-top: var(safe-area-inset-top, 40px); }}/* iPhoneX padding the footer padding-bottom to the bottom */
@supports (bottom: env(safe-area-inset-bottom)){
    body..footer{
        padding-bottom: constant(safe-area-inset-bottom, 20px);
        padding-bottom: env(safe-area-inset-bottom, 20px);
        padding-top: var(safe-area-inset-bottom, 20px); }}Copy the code

safe-area-inset-top, safe-area-inset-right, safe-area-inset-bottom, Safe-area-inset -left Safe-area-inset -* consists of four environment variables that define the top, right, bottom, and left rectangles inside the viewport edge so that content can be safely placed without the risk of being cut off by a non-rectangular display.

For a rectangular viewport, such as a regular laptop monitor, the value is zero.

For non-rectangular displays (such as round dials, iPhoneX screens), all content is visible within the rectangle formed by the four values set by the user agent.

Env (

,

?) , the first parameter is the custom region, and the second parameter is the alternate value.

Var () : var(

,

?) Is used to give an alternate value if env() is not in effect.

Constant () was drafted by CSS 2017-2018 and it is unknown whether it has been standardized. It is unknown whether this function is available in other iOS browser versions, but added for compatibility purposes.

See resources at the end of this article for details.


7. The page becomes a problem with pictures and QR codes

performance

There is a need to generate pictures or TWO-DIMENSIONAL code on the page at work. Probably the first thing that comes to mind is that it’s easier to hand it over to the back end. But in this way, we need to pass all the page code to the back end, which consumes too much network performance.

The solution
Generate qr code

Generate a QRCode using QRCode

import QRCode from 'qrcode';
// Use async to generate images
const options = {};
const url = window.location.href;
async url => {
  try {
    console.log(await QRCode.toDataURL(url, options))
  } catch (err) {
    console.error(err); }}Copy the code

Assign await qrcode.todataURL (URL, options) to the image URL

Generate images

HtmlToCanvas is mainly used to generate canvas canvas

import html2canvas from 'html2canvas';
html2canvas(document.body).then(function(canvas) {
    document.body.appendChild(canvas);
});
Copy the code

But it’s not just here, because it’s canvas. Mobile generated images are blurry.

We use a new canvas method to generate multiple times and put it into a double container to achieve a clearer effect. It is simply realized by downloading pictures and files through hyperlink, and a more complete implementation method will be updated later

const scaleSize = 2;
const newCanvas = document.createElement("canvas");
const target = document.querySelector('div');
const width = parseInt(window.getComputedStyle(target).width);
const height = parseInt(window.getComputedStyle(target).height);
newCanvas.width = width * scaleSize;
newCanvas.height = widthh * scaleSize;
newCanvas.style.width = width + "px";
newCanvas.style.height =width + "px";
const context = newCanvas.getContext("2d");
context.scale(scaleSize, scaleSize);
html2canvas(document.querySelector('.demo'), { canvas: newCanvas }).then(function(canvas) {
  // Simply set the download function via the hyperlink
  document.querySelector(".btn").setAttribute('href', canvas.toDataURL());
}
Copy the code

Set the scaleSize size as required


8. Wechat public account sharing problems

performance

In the development of wechat public account H5, click the share button inside the page to invoke SDK, but the method does not take effect.

The solution

Add a layer of mask for sharing guidance.

Because click the share button inside the page cannot be called directly, and the share function needs to click more in the upper right corner to operate.


9.H5 invokes sdK-related solutions

Native communication with H5

The solution

Support iOS and Android with DSBridge

See Resources for documentation

The SDK team provides the method
  1. Registration methodbridge.register
bridge.register('enterApp'.function() {
  broadcast.emit('ENTER_APP')})Copy the code
  1. The callback methodbridge.call
export const getSDKVersion = () = > bridge.call('BLT.getSDKVersion')
Copy the code
Event listening and triggering methods
const broadcast = {
  on: function(name, fn, pluralable) {
    this._on(name, fn, pluralable, false)},once: function(name, fn, pluralable) {
    this._on(name, fn, pluralable, true)},_on: function(name, fn, pluralable, once) {
    let eventData = broadcast.data
    let fnObj = { fn: fn, once: once }
    if (pluralable && Object.prototype.hasOwnProperty.call(eventData, 'name')) {
      eventData[name].push(fnObj)
    } else {
      eventData[name] = [fnObj]
    }
    return this
  },
  emit: function(name, data, thisArg) {
    let fn, fnList, i, len
    thisArg = thisArg || null
    fnList = broadcast.data[name] || []
    for (i = 0, len = fnList.length; i < len; i++) {
      fn = fnList[i].fn
      fn.apply(thisArg, [data, name])
      if (fnList[i].once) {
        fnList.splice(i, 1)
        i--
        len--
      }
    }
    return this
  },
  data: {}}export default broadcast

Copy the code
Note on pit

Before calling a method, make sure that the SDK provides the method. If Android provides the method, iOS calls will show a popup window such as method call failure. How do you solve it?

Provide a check whether Android, iOS. Judge according to the device

export const hasNativeMethod = (name) = >
  return bridge.hasNativeMethod('BYJ.' + name)
}

export const getSDKVersion = function() {
  if (hasNativeMethod('getSDKVersion')) {
    bridge.call('BYJ.getSDKVersion')}}Copy the code

The same function requires the same iOS and Android method name, so it is easier to handle oh


10.H5 Debug related scheme policies

performance

Debugging code is generally about looking at data and locating bugs. There are two scenarios, one is debugging during development and testing, and the other is debugging in production environment.

Why is there debugging on production? There are times when this bug cannot be replicated in the test environment and the test environment is inconsistent with the production environment, requiring urgent production debugging.

While developing on the PC side, you can simply drop out of the console and use the tools provided by the browser to operate DevTools or view the logs. But what do we do inside the App?

Principles and solutions
1. vconsoleConsole plug-in

It’s easy to use

import Vconsole from 'vconsole'
new Vconsole()
Copy the code

Interested in seeing the fundamentals of its implementation, the point we should focus on is how vsConsole prints out all our logs for Tencent open source Vconsole

The above methods are for development and testing purposes only. It is not allowed in the production environment, so you need to judge the environment when using it.

import Vconsole from 'vconsole'
if(process.env.NODE_ENV ! = ='production') {
    new Vconsole()
}
Copy the code
2. Agent + Spy – Debugger

It’s a little bit tricky to do, but I’ll write it out in detail, basically in 4 steps

  1. Installing plug-ins (global installation)
sudo npm install spy-debugger -g
Copy the code
  1. Mobile phone and computer under the same wifi, mobile phone set agent

Set the HTTP proxy IP address of the mobile phone to the IP address of the PC and the port to the spy-Debugger startup port

Spy – Debugger default port: 9888

Android: Settings – WLAN – Long press Select Network – Modify Network – Advanced – Proxy Settings – Manual

IOS: Settings – Wi-Fi – Select the network, click the exclamation mark, HTTP proxy manual

  1. Open the H5 page in the browser or APP
  2. Open the desktop log site for debugging and click on the NPM console to listen for the address. View the packet capture and H5 page structure

This approach allows you to debug the generated environment’s pages without modifying the code and can handle most debugging requirements

Reference: small lock jun less

12 mobile terminal 100vh problems

Problem Description:

Full screen scrolling is required on scrolling phones (swiper is used). The 100vh layout is used because the height of the mobile terminal is variable, which is very harmonious in the simulator. As a result, the browser bar and some navigation bar title bar appear differently in Chrome and wechat/Safari browsers on mobile terminals

Presentation 1: The swiper plugin is set to innerHeight, causing a fault in the scrolling of the wechat browser

Rendering 2:100vh is actually too high for the screen, causing some content to be blocked

Causes of occurrence:

It’s best to avoid 100vh and instead rely on javascript to set the height for a complete viewport experience.

The core problem is that mobile browsers (Chrome and Safari) have a “help” feature that makes the address bar sometimes visible and sometimes hidden, changing the size of the viewport,

Instead of making the height of 100vh visible on the screen when the viewport height changes, these browsers set 100vh to the height of the browser that hides the address bar. As a result, the bottom part of the screen will be cut off when the address bar is visible, destroying the purpose of 100Vh.

A 3:

When we use the iOS Safari browser, the toolbar and address bar are hidden when we swipe the page.

When the page slides up, the toolbar is hidden and the window.innerHeight changes, but the CSS VH does not change. 100vh = window.innerHeight when the toolbar is hidden. (on IphoneXR, window.innerHeight = 719px with toolbar displayed and window.innerHeight = 833px with toolbar hidden)

It doesn’t matter if your page is designed to be a long slide, but if your page is designed to be a single-page application the size of a viewport, that’s a problem. Because even if you set width to 100%, the page will still scroll, and when you scroll up to a certain threshold, the toolbar will hide and the layout will be completely confused. And the height of the toolbar is different in landscape and portrait.

Also, if we set the absolute or fixed attribute to an element and want to fix it to the bottom, Safari doesn’t do that either. As mentioned above, part of your page is actually blocked by the toolbar at the bottom, so the elements we put at the bottom will also be blocked by the toolbar.

Some solutions:

1. Use calc to dynamically calculate height of objects blocked by nav (not tried)
 min-height: calc(100vh - 0.9 rem) / /0.9 remIt's the height of the obstructionCopy the code
2. Use js to dynamically set the height

Setting the height to window.innerHeight correctly sets the height to the visible part of the window. If the address bar is visible, window.innerHeight is the height of the full screen. If the address bar is hidden, window.innerHeight is the height of the visible part of the screen,

3. Use it in VUE projects

${app}/src/app.vue

  mounted() {
    // First we get the viewport height and we multiple it by 1% to get a value for a vh unit
    let vh = window.innerHeight * 0.01
    // Then we set the value in the --vh custom property to the root of the document
    document.documentElement.style.setProperty('--vh'.`${vh}px`)
    // We listen to the resize event
    window.addEventListener('resize'.() = > {
      // We execute the same script as before
      let vh = window.innerHeight * 0.01
      document.documentElement.style.setProperty('--vh'.`${vh}px`)})},Copy the code

${app}/views/foo.vue

<style lang="scss" scoped>
.container {
  height: 100vh; /* Previously set to 100vh, compatible with some browsers that do not support custom attributes. * /
  height: calc(var(--vh, 1vh) * 100 - 46px);
</style>
Copy the code
Use 4.height:100%

Set each level below the body to a height of 100%

* {
  padding: 0;
  margin: 0;
  border: 0;
  outline: 0;
  box-sizing: border-box;
}
html {
  width: 100%;
  height: 100%;
  border: 5px solid red;
  overflow: hidden;
  // We will try it tomorrow
  height:-webkit-fill-available;
  
}
Copy the code
5. Dynamically resolve the height in MAC Browser, using CSS

The toolbar height is 75px, and calc’s calculated properties are not compatible with earlier versions of Safari

Set each level below the body to a height of 100%

calc(100vh - 75px)
Copy the code
6. Content collapse caused by the lack of parent container height and child height: 100%

Scenario Description:

<head> <style> .app { width: 100%; height: 100%; display: flex; flex: 1; flex-direction: column; } header { width: 100%; height: 75px; } main { flex: 1; } iframe { width: 100%; height: 100%; } </style> </head> <body> <div class="app"> <header></header> <main> <iframe v-if="true"></iframe> <div v-else></div> </main> </div>Copy the code

The parent of an element with a percentage height must have a defined height and must have the height attribute. Otherwise elements with percentage height must default to height: auto(content height)

Chrome automatically fixes this problem, but Safari considers it a bug where the parent of the iframe does not have a given height, causing the iframe height to collapse (along with the content height). So when you stretch the browser window, the actual height of the iframe content changes, causing this problem.

Solution:

  1. Specifies the height of the parent
main { flex: 1; height: calc(100% - 75px); } height: calc(100vh - calc(100vh - 100%))Copy the code
  1. Specify the height of the iframe child directly
iframe { width: 100%; height: calc(100vh - 75px); }
Copy the code

We don’t use 100%-75px because it is 100% dependent on the height specified by the parent, whereas VH is based directly on the browser window height.

7. Use – its – fill – the available

It’s no use (safari)

The CSS

body {
  min-height: 100vh;
  /* mobile viewport bug fix */
  min-height: -webkit-fill-available;
}
html {
  height: -webkit-fill-available;
}
body {
  display: flex; 
  flex-direction: column;
  margin: 0;
  min-height: 100vh;
}

main {
  flex: 1;
}
Copy the code
8. The perfect solution
<template>
  <div class="module">
    <div class="module__item">20%</div>
    <div class="module__item">40%</div>
    <div class="module__item">60%</div>
    <div class="module__item">80%</div>
    <div class="module__item">100%</div>
  </div>
</template>

<script>
export default {
  mounted() {
    // First we get the viewport height and we multiple it by 1% to get a value for a vh unit
    const vh = window.innerHeight * 0.01
    // Then we set the value in the --vh custom property to the root of the document
    document.documentElement.style.setProperty('--vh'.`${vh}px`)

    // We listen to the resize event
    window.addEventListener('resize'.() = > {
      // We execute the same script as before
      const vh = window.innerHeight * 0.01
      document.documentElement.style.setProperty('--vh'.`${vh}px`)}}}</script>

<style>
body {
  background-color: # 333;
}

.module {
  height: 100vh; /* Use vh as a fallback for browsers that do not support Custom Properties */
  height: calc(var(--vh, 1vh) * 100);
  margin: 0 auto;
  max-width: 30%;
}

.module__item {
  align-items: center;
  display: flex;
  height: 20%;
  justify-content: center;
}

.module__item:nth-child(odd) {
  background-color: #fff;
  color: #f73859;
}

.module__item:nth-child(even) {
  background-color: #f73859;
  color: #f1d08a;
}
</style>

Copy the code

13 Safari problems

1. The high default value of the Input tag in Safari

In browser compatibility, the default value of the input tag in Safari is always set to the same height.

If Safari’s input height doesn’t work, be sure to set line-height and remove the iOS UI style: -webkit-appearance: None;

14 Flex Layout Problems (Extensions)

Each unit block in the container is called a Flex item

Spindle space :main size

Cross axis space :cross size

1. The flex container

div{ display: flex | inline-flex; }
Copy the code

When the Flex layout is set, the float, clear, and vertical-align attributes of the child elements are invalidated.

Flex :1’s div height ADAPTS to the remaining height of the screen

2. Set six properties for the Flex container

1. Flex-direction: determine the direction of the main axis (i.e. the alignment of items)
.container {
    flex-direction: row(the default) | row - reverse | column | column - reverse; }Copy the code

2. Flex-wrap: Determines whether items in the container can be wrapped

.container {
    flex-wrap: nowrap(the default) |wrap(project spindle overall size beyond the container line, the first line at the top) | wrap - reverse; (reverse)}Copy the code
  1. Flex-flow: short for flex-direction and flex-wrap (useless)

4. Justify -content: Defines the alignment of items on the main axis.

.container {
    justify-content: 
      flex-start(the default value Left-aligned) |flex-end(right) | center |space-between(full-justified, only two rows, respectively in the fore and aft) |space-around(each project on both sides of the equal interval, projects than the interval between twice with the edge of the interval) | space - evenly child elements will be evenly distributed in the container, at the same time the extra space will quilt elements on either side of the share}Copy the code

Remember that context-content only works if the box has space left to allocate.

5. Align-items: Defines the alignment of items on the cross axis

.container {
    align-items:
      stretch(Default): If the item is not set to height or is set to Auto, it will take up the entire container height. Flex-start center baseline flex-end Center baseline baseline}Copy the code

6. Align-content: Defines the alignment of multiple axes. This property will not work if the project has only one axis

.container {
    align-content: flex-start | flex-end | center | space-between | space-around | stretch(Default value); }Copy the code

When you flex-wrap is set to NowRAP, there is only one axis in the container, and since the project does not wrap, there will be no multiple axes.

When flex-wrap is set to wrap, the container will have multiple axes and you will need to set the alignment between the axes.

Align as justify-content ends/middle/isometric, etc

Flex project properties

1. Order: Defines the order of items in the container. The smaller the value, the higher the order

Order is set so that it can be ranked first.

2. Flex-basis: defines how much space the project occupies on the main axis before allocating extra space. Based on this property, the browser calculates whether there is extra space on the main axis

Default: auto, which is the size of the item, depending on the width or height of the item.

When the main axis is horizontal, the project width is invalidated when flex-basis is set. Flex-basis needs to be used in conjunction with Flex-grow and Flex-shrink to be effective.

  • When the flex-basis value is 0 %, the project is considered zero-sized, so declaring the size 140px is not helpful.
  • When the flex-basis value is auto, then the size is set (say 100px) and the 100px will not be included in the remaining space.

3. Flex-grow: Defines the scale of the project

The default value is 0, that is, if there is free space, it is not enlarged

Flex-grow comes into play when there is still space left after all the items have been sorted with flex-basis values.

If all projects have a flex-Grow attribute of 1, they divide the remaining space equally. (If any)

If one project has a flex-grow attribute of 2 and all the other projects are 1, the former takes up twice as much free space as the other items.

Of course, if you run out of space after all the items are sorted by flex-basis and flex-wrap: nowrap, flex-grow will no longer work, then you need this property.

4. Flex-shrink: Defines the size of the project

Default value: 1, that is, the item will shrink if there is insufficient space. Negative values do not apply to this property.

If the flex-shrink attribute is 0 for one project and 1 for all other projects, the former does not shrink when space is insufficient.

5. Flex: short for flex-grow, flex-shrink and flex-basis

.item{
    flex:  <'flex-grow'> <'flex-shrink'>? || <'flex-basis'>]0 1 auto(Default)}Copy the code

They are as follows:

1. If flex is a non-negative number, the number is flex-grow, flex-shrink is 1, and Flex-basis is 0%

.item {flex: 1; } (Divide the remaining space equally)/ / equivalent to the
.item {
    flex-grow: 1;
    flex-shrink: 1;
    flex-basis: 0%;
}
Copy the code

2. When the flex value is 0, the corresponding three values are 0 1 0%

.item {flex: 0; }(There is residual space, and no amplification)/ / equivalent to the
.item {
    flex-grow: 0;
    flex-shrink: 1;
    flex-basis: 0%;
}
Copy the code

Finally, I beg youattention~~~ I will always try to update!! Be a qualified porter [laughs

This article references many excellent articles by other big names ~ some reference links may not be pointed out but be sure to fill in any omissions ❤

(*^▽^*) In the next chapter, I would like to share with you the answers to the most frequently asked questions in recent interviews.