laitimes

Super detailed explanation of H5 mobile adaptation

author:Not bald programmer
Super detailed explanation of H5 mobile adaptation

Preface

Since the development of the mobile Internet, various mobile devices have come into being, but their physical resolutions can be said to be varied, and in general, UI will provide us with a 375 size design draft, so in order to make the H5 page as consistent as possible on these different devices, the front-end engineer has to adapt the page to the mobile terminal.

Pre-knowledge

Before learning mobile adaptation, we need to understand some relevant pre-knowledge.

Super detailed explanation of H5 mobile adaptation

Screen size

Screen size refers to the length of the screen diagonal in inches. 1 inch = 2.54 centimeters

Electronic devices generally use inches to describe the physical size of the screen, such as 22 or 27 inches, which are common in our computers. The word inch (abbreviated as in) means thumb in Dutch, and one inch is the width of an average person's thumb.

Pixel pixel

From a computer technology point of view, a pixel is the smallest unit that hardware and software can control. It refers to the smallest unit represented on the screen of the display, not the smallest unit on the picture. An image typically contains thousands of pixels, each with its own color information, which are tightly grouped together. "A pixel is a dot, or a very small square."

Screen resolution

Screen resolution refers to the number of pixels that a screen is made up of, and the unit is px.

We can see that there are two kinds of pixels in the above diagram: logical pixels and physical pixels, and their values are different, and there is why the resolution on the design draft provided by the general UI is not the same as the resolution of the real model.

Physical pixels (device pixels)

On the same device, his physical pixels are fixed, that is, the actual number of points decided by the manufacturer when producing the display device, and the size of the physical pixels is different for different devices. (The smallest unit of device control display, we often say 1920*1080 pixel resolution is the physical pixel unit used)

For example, a 21-inch monitor with a resolution of 1440x1080 and a 5.8-inch iPhone X with a resolution of 2436×1125 will be problematic: if we use physical pixels as the unit of measurement, it will look normal on the display and become very small on the iPhone X screen.

Logical pixels (device-independent pixels)

OK,Actually, Joe Gang Leader thought of this problem before,Apple first proposed the concept of Retina Display (retina screen) at the iPhone4 press conference,In the retina screen used in iPhone4,4 pixels are used as 1 pixel,This makes the screen look more exquisite,And in different screens,The size of the same logical pixel is the same。 So high-resolution devices, one more logical pixel. As we can see from the first image, there are still differences in the logical pixels of different devices, but the difference is not as large as the physical pixels, so the problem of mobile pages needs to be adapted. (Device-agnostic logical pixels, representing virtual pixels that can be controlled by the program)

PPI per inch of pixels

PPI (pixel per inch) indicates the number of pixels per inch, the higher the number, the higher the screen can display the image at a higher density.

It is calculated as: PPI=√(X^2+Y^2)/Z (X: number of length pixels; Y: number of width pixels; Z: screen size)

Phones with PPIs between 120-160 are classified as low-density, 160-240 as medium-density, 240-320 as high-density, and above 320 as ultra-high-density

Super detailed explanation of H5 mobile adaptation

Device pixels are more than dpr

"dpr (device pixel ratio)" represents the device pixel ratio, device pixel / device independent pixel, which represents the conversion relationship between device independent pixel and device pixel, which can be obtained through window.devicePixelRatio in JS

The formula is calculated as follows: DPR = Physical Pixel/Logical Pixel

When the device pixel ratio is 1:1, 1 (1×1) device pixels are used to display 1 CSS pixel;

When the device pixel ratio is 2:1, use 4 (2×2) device pixels to display 1 CSS pixel;

When the device pixel ratio is 3:1, 9 (3×3) device pixels are used to display 1 CSS pixel.

Super detailed explanation of H5 mobile adaptation

Conceptual diagram

Screen size, screen resolution - > diagonal resolution / screen size - > screen pixel density PPI|device pixel ratio dpr = physical pixels / device independent pixel dip(dp)|viewport: scale|CSS pixel px

Viewport

Viewport refers to the viewport, which is the area of the webview in the browser or app where the page is displayed. Generally speaking, the viewport on PC refers to the browser window area, while on mobile it is a bit more complicated, it has three viewports:

  • 「layout viewport」:布
  • 「visual viewport」:视觉视口
  • 「ideal viewport」:理

布 (layout viewport)

It is a virtual layout viewport proposed by the browser to solve the problem of the page being displayed on the phone. This viewport can <meta>be changed by setting the viewport with the label. Browsers on mobile devices will set their default viewport to 980px or 1024px (or other values, this is determined by the device), but the consequence is that the browser will have a horizontal scrollbar because the width of the browser's viewport is smaller than the width of the default viewport.

We can get the layout viewport size via document.documentElement.clientWidth

视觉视口(visual viewport)

It refers to the viewable area of the browser, which is the area that we can see on mobile devices. By default, it is equal to the current browser window size, and when the user scales the browser, the size of the layout viewport is not changed, but the size of the visual window is changed.

Super detailed explanation of H5 mobile adaptation

We can use window.innerWidth to get the visual viewport size.

理想视口(ideal viewport)

The ideal viewport. This concept was first proposed by Apple, and other browser vendors have followed suit, with the aim of solving the problem of page elements being too small in the layout viewport, so that the page displayed in the ideal viewport has the optimal width and the user does not need to zoom. The so-called ideal viewport, that is, the page drawing area can perfectly adapt to the viewport size of the device width, and all the content of the website can be viewed normally without scrolling bars, and the text and pictures are clear, such as the ideal viewport width for all iPhones is 320px, and the ideal viewport for Android devices is 320px, 360px, etc.

When the page zoom is 100%, the ideal viewport = the visual viewport.

We can use screen.width to get the ideal viewport size.

Meta viewport

For mobile pages, you can use <meta>labels to configure viewport size, scale, and so on.

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />           
  • "width": This property is used to control the width of the viewport, you can set the width to the exact number of pixels such as 320, or you can set it to a keyword such as device-width, which indicates the actual width of the device.
  • "height": This property is used to control the height of the viewport, you can set the height to the exact number of pixels such as 640, or you can set it to a keyword such as device-height to indicate the actual height of the device.
  • "initial-scale": This property is used to specify the initial zoom of the page, you can configure the number of 0.0~10, "initial-scale=1 means that no zoom is performed, the viewport is just equal to the ideal viewport", when it is greater than 1, it means that the viewport is enlarged, and when it is less than 1, it means that it is reduced. This only represents the initial viewport zoom value, but users can also zoom by themselves, such as two-finger drag gesture zoom or double-click gesture zoom. "Initial-scale default value on Android devices: " There is no default value, you must set it for this property to work. On iPhone and iPad, no matter how wide you set the viewport, if you don't specify a default zoom value, the iPhone and iPad will "automatically calculate the zoom value" so that the current page does not appear a horizontal scrollbar (or the width of the viewport is the width of the screen).
  • "maximum-scale": This attribute indicates the maximum scale that the user can manually zoom in, and the number of 0.0~10 can be configured.
  • "minimum-scale": This property is similar to maximum-scale, which is used to specify the minimum scale of page reduction. Typically, the value of the property is not defined, and the page is too small to navigate.
  • "user-scalable": indicates whether to allow users to manually scale, and can be configured to no or yes. If no is set, users will not be able to zoom or out of the page by gestures.

It should be noted here that viewport is only valid for mobile browsers, not for PC browsers.

Adapt and scale

In order to make the mobile page get a better display effect, we must make the layout viewport and visual viewport equal to the ideal viewport as much as possible, so we generally set width=device-width, which is equivalent to making the layout viewport equal to the ideal viewport, and setting initial-scale=1.0 is equivalent to making the visual viewport equal to the ideal viewport;

As mentioned above, width determines the width of the layout viewport, but it is not the only determining factor in the layout viewport, and setting initial-scale can also affect the layout viewport, because the layout viewport width is the maximum value of width and the width of the visual viewport.

For example, if the ideal viewport width of the mobile phone is 400px, set width=device-width and initial-scale=2, then the visual viewport width = ideal viewport width / initial-scale is 200px, and the layout viewport takes the maximum value of the two, that is, device-width 400px.

If width=device-width and initial-scale=0.5 are set, the visual viewport width = ideal viewport width / initial-scale is 800px, and the layout viewport takes the maximum value of the two values, which is 800px.

Mobile adaptation solutions

When we are doing H5 mobile development, the most used unit is PX, which is a CSS pixel, when the page zoom ratio is 1:1, a CSS pixel is equal to a device-independent pixel. However, CSS pixels can be easily changed, for example, when a user zooms in on a page, the CSS pixels will be enlarged, and the CSS pixels will span more device pixels.

Page zoom factor = CSS pixel / device-independent pixel

REM adaptation

rem (font size of the root element) is a new relative unit in CSS3, which refers to the unit of font size relative to the root element.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
    <title>Document</title>
    <style>
        *{margin:0;padding:0}
        .box{
            width: 10rem;
            height: 4rem;
            background-color: antiquewhite;
            font-size: 0.53rem; /* 20px*/
        }
    </style>
    <script>
        function setRootRem() {
            const root = document.documentElement;
            /** 以iPhone6为例:布局视口为375px,我们把它分成10份,则1rem = 37.5px,
             * 这时UI给定一个元素的宽为375px(设备独立像素),
             * 我们只需要将它设置为375 / 37.5 = 10rem。
            */
            const scale = root.clientWidth / 10
            root.style.fontSize = scale + 'px'  
        }
        setRootRem()
        window.addEventListener('resize', setRootRem)
    </script>
</head>
<body>
    <div class="box">eee</div>
</body>
</html>           
Super detailed explanation of H5 mobile adaptation

Ok, here we can see that when we test with different devices, the font-size of the root node will change with the width of the layout viewport of the device, so the width of the element here 10rem will always be equal to the width of the current layout viewport, and the font-size will also change with the change of equipment. This is the so-called mobile adaptation, in fact, this solution was first proposed by Ali as an open-source mobile adaptation solution flexible, and the principle is very simple.

But then we will find that it will be very complicated when writing the layout, that is, you need to manually calculate the corresponding rem value by yourself, for example, the font-size design above is 20px, then we need to calculate what the rem corresponding to 20px is, according to our above rules, "1px = 1/37.5rem", so 20px should correspond to 20/37.5 = 0.53rem. So we usually use this solution with a CSS preprocessor

"rem with CSS preprocessor"

Here I will use vue+less to operate simply, which can be encapsulated to the bottom layer, and here I will demonstrate the principle for the time being.

Here it is recommended to use the self-made scaffolding songyao-cli to quickly generate a vue project, and after installing the dependencies, start configuring less.

/*rem.less*/
@device-width: 375; /*设备布局视口*/
@rem: (@device-width/10rem);           

Then configure the @rem as a less global variable

//vue.config.js
module.exports = {
    css: {
        loaderOptions:{
            less: {
                additionalData: ` @import '~@/static/rem.less';`
            }
        }
    }
}           

Configure the method of calculating rem in the VUE entry file

// toRem.js
export default function() {
    const root = document.documentElement;
    /** 以iPhone6为例:布局视口为375px,我们把它分成10份,则1rem = 37.5px,
     * 这时UI给定一个元素的宽为375px(设备独立像素),
     * 我们只需要将它设置为375 / 37.5 = 10rem。
    */
    const scale = root.clientWidth / 10
    root.style.fontSize = scale + 'px'  
}


//main.js
import Vue from 'vue'
import App from './App.vue'
import toRem from "./utils/toRem" //
toRem()
window.addEventListener('resize', toRem)
Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')           

Then you can use global variables in Vue @rem for mobile development

<template>
    <div class="songyao">
        <h1>{{ username }}</h1>
    <p>
      了解脚手架及脚手架指令请移步个人博客<br>
      check out the
      <a href="http://47.100.126.169/zmengBlog" target="_blank" rel="noopener">逐梦博客</a>.
    </p>
    <p>微信公众号:<span class="wx_name">前端南玖</span></p>
    </div>
</template>

<script>
export default {
    name: 'songyao',
    data() {
        return {
            username: 'songyao-cli(vue 模板)'
        }
    },
}
</script>

<style lang="less">
.songyao{
    h1{
        font-size: (24/@rem);
    }
    p{
        font-size: (16/@rem);
    }
   .wx_name{
    color:brown;
    }
}

</style>           
Super detailed explanation of H5 mobile adaptation

However, the above scheme is a transitional scheme, viewport is a scheme proposed by Apple, and the compatibility of major browsers was not very good before, so there is this REM adaptation scheme.

There is a sentence in the flexible documentation of the Ali open source library:

Since viewport units are compatible with many browsers, the transition solution of lib-flexible can be abandoned, and there are certain problems with both the current version and the previous version. It is recommended that you start using viewport instead of this side.

Yes, this solution is slowly being abandoned, but there are still many companies using it.

VW and VH adaptation

vw (Viewport Width) and vh (Viewport Height) are units based on the view window, which are proposed in CSS3 and are based on the units of the view window.

The vh and vw schemes divide the visual viewport width window.innerWidth and the visual viewport height window.innerHeight into 100 parts.

The flexible scheme above mimics this one, as VW was not well compatible earlier.

  • vw(Viewport's width):1vw等于视觉视口的1%
  • vh(Viewport's height): 1vh is 1% of the visual viewport height
  • vmin: The lesser of vw and vh
  • vmax : Choose the greater of vw and vh

If we press the visual viewport to 375px, then 1vw = 3.75px, then the UI gives an element a width of 75px (device-independent pixels), we just need to set it to 75 / 3.75 = 20vw.

Here we can also use less to achieve, we don't have to manually calculate, we just leave the calculation process to less, we can develop it directly according to the design draft

// 还是rem.less 我们加一个@vw变量
@device-width: 375;
@rem: (@device-width/10rem);
@vw: (100vw/@device-width);           
<template>
    <div class="songyao">
        <h1>{{ username }}</h1>
    <p>
      了解脚手架及脚手架指令请移步个人博客<br>
      check out the
      <a href="http://47.100.126.169/zmengBlog" target="_blank" rel="noopener">逐梦博客</a>.
    </p>
    <p>微信公众号:<span class="wx_name">前端南玖</span></p>
    </div>
</template>

<script>
export default {
    name: 'songyao',
    data() {
        return {
            username: 'songyao-cli(vue 模板)'
        }
    },
}
</script>

<style lang="less">
.songyao{
    h1{
        // font-size: (24/@rem);
        font-size: 24*@vw;
    }
    p{
        // font-size: (16/@rem);
        font-size: 16*@vw;
    }
   .wx_name{
    color:brown;
    }
}

</style>           
Super detailed explanation of H5 mobile adaptation

viewport+PX

OK, let's talk about a viewport solution recommended by the flexible team. This solution allows us to develop without paying attention to the difference in the screen size of the device, and directly develop according to the annotations on the design draft, and do not need to convert units, and directly use px.

Add <meta name="viewport" content="width={design width}, initial-scale={screen logic pixel width/design width}" > to the head tag of the HTML.

If the UI gives us a design width of 375px, we need to set the width of the page's viewport to 375, and then scale the page as a whole according to the device's logical pixels.

export function initViewport() {
    const width = 375;  // 设计稿宽度
    const scale = window.innerWidth / width
    // console.log('scale', scale)
    let meta = document.querySelector('meta[name=viewport]')
    let content = `width=${width}, init-scale=${scale}, user-scalable=no`
    if(!meta) {
        meta = document.createElement('meta')
        meta.setAttribute('name', 'viewport')
        document.head.appendChild(meta)
    }
    meta.setAttribute('content', content)
}           
<template>
    <div class="songyao">
        <h1 class="name_rem">{{ username }}</h1>
        <h1 class="name_vw">{{ username }}</h1>
        <h1 class="name_px">{{ username }}</h1>
    <p>
      了解脚手架及脚手架指令请移步个人博客<br>
      check out the
      <a href="http://47.100.126.169/zmengBlog" target="_blank" rel="noopener">逐梦博客</a>.
    </p>
    <p>微信公众号:<span class="wx_name">前端南玖</span></p>
    </div>
</template>

<script>
export default {
    name: 'songyao',
    data() {
        return {
            username: 'songyao-cli(vue 模板)'
        }
    },
}
</script>

<style lang="less">
.songyao{
    p{
        // font-size: (16/@rem);
        font-size: 16*@vw;
    }
    .name_rem{
        font-size: (24/@rem);
    }
    .name_vw{
        font-size: 24*@vw;
    }
    .name_px{
        font-size: 24px;
    }
   .wx_name{
    color:brown;
    }
}

</style>           

Here we put the three schemes together and compare, all of them correspond to 24px on the 375 design draft, and the three schemes are basically the same.

Super detailed explanation of H5 mobile adaptation

summary

At present, these three solutions are the most commonly used solutions, and they all have their own advantages and disadvantages.

"REM Solution"

  • The adaptation principle is slightly more complicated
  • JS is required
  • The conversion of PX to CSS is simple to calculate
  • The scheme is flexible, and can achieve both global scaling and partial non-scaling

"VW Solution"

  • The adaptation principle is simple
  • You don't need JS to adapt
  • The VW of the PX to CSS annotation in the design draft is complicated
  • The scheme is flexible, and can achieve both global scaling and partial non-scaling

「viewport+px 」

  • The adaptation principle is simple
  • JS is required
  • Annotation directly with the design draft does not require conversion
  • The scheme is rigid and can only achieve page-level limb scaling

Read on