One, foreword

Over the past few years, as the mobile Web has grown wildly and the Android and IOS camps have competed on smartphones, multiple versions of the system have emerged. There are a variety of screen sizes, display technologies (like the Retina display), and THE W3C standards for CSS are patchy across a wide variety of mobile browsers.

Look down mobile Web development work is facing a lot of diversity, it is conceivable in such uncertainty on developing a perfect project will have how much resistance, therefore, mobile Web needs to be a perfect mature adaptation scheme to smooth the difference between the diversity and the insufficiency, provides a relatively stable and controllable development environment.

This article only introduces CSS style layout adaptation solutions, as for HTML5 and JavaScript adaptation solutions, in fact, there are some mature solutions, such as Babel, various polyfill, and so on, and with Webpack use more fragrant.

Second, Flexible solution

Flexible scheme is mainly a set of solutions that use THE ability of JavaScript to control viewport and rem to simulate the characteristics of VW to achieve the purpose of adaptation.

Flexible scheme implementation involves a lot more and use PC development rarely come into contact with the concept of what actually whether adaptation scheme is based on carding and the management of these concepts, therefore, to our understanding of these concepts and to explore the deep principle is especially important of mobile terminal adapter (please see the specific concept about a simple mobile terminal adapter).

2.1 Core idea of Flexible

2.1.1 Use REM to simulate VW for a variety of screen sizes

Rem is a calculated attribute value calculated relative to the font size of the HTML element. You can unify the layout of the entire page by setting the fontSize property value for the documentElement.

// set 1rem = viewWidth / 10 function setRemUnit () { var rem = docEl.clientWidth / 10 // Docel.style. fontSize = rem + 'px'} setRemUnit();Copy the code

As shown in the code above, Flexible cuts the width of the entire page into 10 pieces, and then sets 1/10 of the calculated page width to the fontSize of the HTML node, which means that rem is then applied to the HTML node children of the current page in proportion to the page.

2.1.2 Control the width and scale values of viewport for high-power screen display

Set the width of the viewport to device-width, and change the default width of the browser viewport (layout viewport and visual viewport) to the desired viewport width so that the user can see the full layout viewport content within the desired viewport.

Set the viewport’s initial-scale, maximum-scale and minimum-scale values equally, so that 1 physical pixel = 1CSS pixel is suitable for high-magnification screen display (this is where we avoid the well-known “1px problem”).

var metaEL= doc.querySelector('meta[name="viewport"]');
var dpr = window.devicePixelRatio;
var scale = 1 / dpr
metaEl.setAttribute('content', 'width=device-width, initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no'); 
Copy the code

2.2 Flexible matching peripheral tools

2.2.1 PostCSS – px2rem

Flexible uses REM as the standard layout unit and splits page widths into 10 equal parts, so when writing CSS code you need to calculate the rem value of the current PX unit on the current draft. Take iPhone6 as an example: the layout viewport is 375px, so 1REM = 37.5px. At this time, the width of an element given in the design is 75px (device-independent pixels), so we only need to set it to 75/37.5 = 2REM.

Of course, the above work mode is obviously inefficient and unacceptable, we can use PostCSS pxtorem plug-in to help us complete the calculation process:

plugins: { ... , 'postCSs-pxtorem ': {rootValue: 75, // After converting to REM, keep several decimal places unitPrecision: 5, /** * will be converted CSS properties list, * set to * for all, ['*','*position*','! Letter-spacing ','! Font *'] ** position* for all properties containing position*! Letter-spacing indicates non-letter-spacing *! Font * indicates non-font-size font-weight... Properties * */ propList: ['*', '! Letter-spacing '], // The class selector name that will not be converted, supports the regular selectorBlackList: ['.rem-'], replace: MediaQuery: false, minPixelValue: 1}}Copy the code

The above code is based on Vue cli3. x Webpack project, only need to configure in the current project root directory postcss.config.js, in addition to Webpack configuration, you can also use other configuration methods, detailed introduction can be click here to understand.

Postcss-pxtorem can help us to convert the px value we need to convert to the corresponding REM value, such as:

.name-item {
    font-size: 40px;
  line-height: 56px;
  margin-left: 144px;
  border-top: 1PX solid #eeeeee;
  color: #333333;
}
Copy the code

The conversion looks like this:

.name-item { font-size: .53333rem; line-height: .74667rem; font-weight: 700; Margin - left: 1.92 rem; border-top: 1px solid #eee; color: #333; }Copy the code

2.3 Defects of Flexible

2.3.1 Incompatible use of IFrame.

That is, the content displayed in iframe still uses CSS pixels, which will cause problems under high power screen. For example, when we use iframe to reference a video playing resource of Tencent Video, the play button of the video player will be displayed differently on different DPR devices:



As you can see, the play button is much larger on a DPR = 2 device than it is on a DPR = 3 device. If you measure it carefully, you will find that it is exactly 1.5 times larger. If you read the simple mobile adaptation, it is easy to understand why, but we won’t go into it here.

2.3.2 Android phones with high-power screens are not processed

If you have researched the lib-Flexible source code, then you must know that Lib-Flexible has a special processing for Android phones, that is, always press DPR = 1 processing.

If (isIPhone) {// In iOS, for 2 and 3 screens, use 2x solution, and for the rest, use 1x solution if (devicePixelRatio >= 3 && (! dpr || dpr >= 3)) { dpr = 3; } else if (devicePixelRatio >= 2 && (! dpr || dpr >= 2)){ dpr = 2; } else { dpr = 1; }} else {// For other devices, use the same scheme DPR = 1; }Copy the code

So why doesn’t Flexible adapt to Android’s higher power screens? I think Flexible has a reason for this: Over the years, Android phones have had a range of DPR values ranging from 1 to 4 to 5, with 1.75, 2.6, and 3.5 among them. So Flexible under the tradeoff directly simple and rough android hand all press DPR = 1 processing, also can be a quick cut to the confusion.

Of course, we can also manually modify the lib-Flexible source code to make up for this flaw, but we can only apply it to android devices with integer DPR, and ignore the weird DPR. However, who knows what the maximum integer value of DPR is for Android phones? God knows (Samsung S8’s DPR is 4)

2.3.3 Incompatible responsive layout

Responsive layout, its substantive approach is combined with cSS3 media query @media to do specific layout design for some different size threshold, such as the use of compact layout for the screen below 768px, the screen from 769px to 992px to do mixed text layout, the screen greater than 992px to do rich elements, multi-element layout.

.main-content { max-width: 70em } @media screen and (min-width: 0) {.main-content {margin:0 6.4935064935%}} @media screen and (min-width: 1) {.main-content {margin:0 6.4935064935%}} @media screen and (min-width: 1) Margin :0 5.1282051282%}} @media screen and (min-width: 1em) {.main-content {margin:0 5.1282051282%}} @media screen and (min-width: 1em) {.main-content {margin:0 5.1282051282%}}Copy the code

Among them, the size query statement involved in the @media syntax is based on the physical pixels of the current device, which is contrary to the Flexible layout theory (that is, to scale the viewport by equal proportion for different DPR devices, so as to change the layout viewport size and visual viewport size simultaneously). Therefore, responsive layouts do not work well in “isometric zoom viewport size” situations.

2.3.4 Failed to properly respond to system font size

Flexible is used to set the font size of the HTML element to ensure that all elements on the page are styled in REM with respect to the font size of the HTML element.

However, in the wechat environment (or in other Web browsers with font sizes that can be set, such as Safari), if you set the font size for wechat and then open the Flexible Web page, you will find that the page layout is out of order and all elements with REM size are larger. The font size of the HTML is still the same, but the element is larger.

In fact, though Flexible helps us use it<meta/>Tag is setwidth=device-widthanduser-scalable=noAnd the correspondingscaleScale values to ensure that our element size is at high magnification (dpr >= 2 ), but after adjusting the font size of the Web browser, our “viewport” also responds to a proportional reduction in size, i.e. the visual viewport (window.innerWidth), it suddenly became clear that it was not our elements that became larger, but our visual viewports that became smaller!



Based on the knowledge we have learned about viewports, the root cause is that when we adjust the font size of the Web browser, we also adjust the scale value of the viewport in response, thus resulting in a smaller visual viewport.

Knowing the cause of the Bug, can we solve it? The answer is that it doesn’t work with Flexible, but it works perfectly with Viewport. Flexible’s historic mission is done. Let’s drop Flexible and embrace the new change.

3. Viewport scheme

The Viewport solution mainly uses the

Units VW, vH, vmax, and vmin of CSS Values and Units Module Level 3 (recommended) in CSS3. By definition, they are relative units, and their relative frame of reference is a “visual viewport “:

unit Relative to (reference unit)
‘vw’ 1% of viewport’s width
‘vh’ 1% of viewport’s height
‘vmax’ 1% of viewport’s larger dimension (vw and vh)
‘vmin’ 1% of Viewport’s Smaller Dimension (larger value in VW and VH)

The vmin and vmax values are calculated from the larger dimension of the Viewport. If window.innerheight > window.innerWidth, the vmin value is window.innerWidth / 100. The vmax value is window.innerheight / 100.

We can use Caniuse to check the compatibility of Viewport units on various major browser versions:



As you can see from the graph, most of the major browsers already support the ViewPort unit. Some of the browser versions in light green are partially supported, which are not compatible with vmax and Vmin usage. Some of the known issues listed in the “Know Issues” column are mostly about users scaling viewPort sizes or buggy behaviors unique to IOS 7 Safari, which we can control.

In fact, our adaptation scheme is better called “VW adaptation scheme” than “Viewport adaptation scheme”, because in our adaptation scheme, we only need to use VW as a relative unit, and its compatibility is the best, and other units are basically unavailable.

It’s 9102 years since IOS 7 was released on September 18,2013, and will be available as a free download at 1am on September 19,2013. Add in the fact that the iPhone allows you to change the speed limit without updating the system, and the probability of this ancient system reappearing is almost zero.

3.1 The core idea of Viewport scheme

3.1.1 Use VW as the layout unit of elements

Vw, as a layout unit, fundamentally solves the problem of screen adaptation of different sizes from the bottom, because the percentage of each screen is fixed, predictable and controllable.

Starting from our actual development work, we all use the unified visual design draft of iPhone6 (width 750px), so 100VW =750px, that is, 1vw = 7.5px. Therefore, if the width of an element on the design is value pixel, the corresponding VW value can be calculated by vw = value / 7.5.

It should be noted that although VW painlessly solves many of the problems we have encountered before, it is not a panacea. Through searching materials, blogs and testing practices, we can safely use VW to adapt our pages in the following scenarios:

• Container fit, you can use VW • text fit, you can use VW • borders, rounded corners, and shadows greater than 1px can use VW • Inside margins and margins can use VW

3.1.2 Incompatible degradation processing

Most of the mainstream browsers we know naturally support VW units, but it is not ruled out that some versions of some browsers are incompatible. If business needs, we can downgrade them in the following two ways:

• CSS Houdini: The CSS Houdini handles VW. It calls the CSSUnitValue API provided by CSS Typed DOM Level1. • CSS Polifill: respond with corresponding polyfills. Currently, polyfills for VW Units mainly include vminPoly, Viewport Units Buggyfill, Vunits. js and Modernizr. Viewport Units Buggyfill is recommended by Damo Teacher

3.2 Peripheral tools compatible with the Viewport solution

3.2.1 postcss – px – to – the viewport

The postCSs-pxtorem plugin is used to convert px units to vw, VH, vmin, or vmax Windows. It is also one of the core plug-ins of the ViewPort adaptation scheme.

When configuring the webpack project, you only need to configure it in postcss.config.js under the root directory of the project. The basic configuration items are as follows:

Plugins: {'postcss-px-to-viewport': {unitToConvert: 'px', // Unit viewportWidth: 750, // Viewport width, the same as the design text width unitPrecision: 5, // Accurate to a few decimal places /** * list of CSS properties to be converted, * set to * to indicate all, e.g. ['*'] * set * before or after the property, e.g. ['*position*'], *position* indicates all attributes containing position, such as background-position-y * set to! Xx indicates properties that do not match XX, for example: ['! Letter-spacing '] indicates properties other than the letter-spacing property * Can also be used! And *, such as ['! Font *'] in addition to font size, font weight... * */ propList: ['*'], viewportUnit: 'vw', // The unit to be converted to fontViewportUnit: 'vw',// to convert called font units /** * to ignore selectors, that is, the corresponding property values of these selectors are not converted * to a string, the converter will ignore those selectors that contain the string when converting, such as: ['body'] will match.body-class, which means that the style setting for. Body-class will not be converted to a regular expression. The selector will be checked to see if it matches the regular expression. For example, [/^body$/] will match body but not.body */ selectorBlackList: [], minPixelValue: 1, // Minimum pixel value mediaQuery: False, // Whether to convert the property value set in the media query. Replace: True, // Replace the rule that contains VW instead of adding a fallback /** * Ignore some files, such as 'node_modules' * set to regular expression, will ignore all files that match that re * if set to array, Exclude: [], landscape: false, // If @media (orientation: LandscapeUnit: 'vw', // landscapeWidth: 1334 // landscapeWidth}Copy the code

Currently, we use 750px width for the visual design draft, so 100VW = 750px, that is, 1vw = 7.5px. Then we can directly convert the px value on the design drawing into the corresponding VW value. Postcss-px-to-viewport will automatically convert the px calculation to the corresponding VW value, for example:

.name-item {
    font-size: 40px;
  line-height: 56px;
  margin-left: 144px;
  border-top: 1PX solid #eeeeee;
  color: #333333;
}
Copy the code

After the transformation:

.name - item {the font - size: 5.33333 vw; The line - height: 7.46667 vw; Margin - left: 19.2 vw; border-top: 1px solid #eee; color: #333; }Copy the code

Of course, postcss-px-to-viewport does more than that. It can also set some keywords or regulars in the selectorBlackList option to avoid converting these specified selectorBlackList, such as selectorBlackList: [‘ ignore ‘, ‘hairlines’] :

<div class="box ignore"></div> write CSS when:. Ignore {margin: 10px; background-color: red; } .box { width: 180px; height: 300px; }. Hairlines {border-bottom: 0.5px solid red; }Copy the code

After transformation:

.box { width: 24vw; height: 40vw; } .ignore { margin: 10px; /*. Box element with. Ignore class name */ background-color: red; }. Hairlines {border-bottom: 0.5px solid red; }Copy the code
3.2.2 Viewport Units Buggyfill

This js library is intended to be compatible with browsers that are not compatible with VW, VH, vmax and vmin viewport units. As we made clear at the beginning of the solution, most browsers on most models today are compatible with viewPort units. Damo teacher conducted a test on Top30 popular models in 2017, among which only the following models do not fully support viewport units:

However, if your business doesn’t allow for your project to run on many older models or browser versions, then you have to consider some hacks, and this js library is your first choice.

3.2.2.1 Usage
1. Introduce JavaScript files

Viewport-units-buggyfill consists of two JavaScript files: viewport-units-buggyfill. Js and viewPort-units-buggyfill. Hacks.js. You just need to include these two files in your HTML file. For example, introducing them in index.html in the Vue project:

<script SRC = "/ / g.alicdn.com/fdilab/lib3rd/viewport-units-buggyfill/0.6.2/??viewport-units-buggyfill.hacks.min.js, viewport - units - buggyfill.min.js"></script>Copy the code
2. Call viewPort-units-BuggyFill in the HTML file

After introducing the polyfill location in the HTML file, you need to manually call viewport-units-BuggyFill:

<script>
  window.onload = function () {
    window.viewportUnitsBuggyfill.init({
      hacks: window.viewportUnitsBuggyfillHacks
    });
}
</script>  
Copy the code
3. Combine postCSs-viewport-units

Specific use. In your CSS, whenever you use a viewport unit, you need to add content to the style:

.my-viewport-units-using-thingie { width: 50vmin; height: 50vmax; top: calc(50vh - 100px); left: calc(50vw - 100px); /* hack to engage viewport-units-buggyfill */ content: 'viewport-units-buggyfill; width: 50vmin; height: 50vmax; top: calc(50vh - 100px); left: calc(50vw - 100px); '; }Copy the code

This might make you sick, and we can’t do human calculations every time we write a VW. Especially in our scenario, we used the plug-in postCSS-px-to-viewport to convert VW, and we couldn’t add the content manually.

This is where the postCSS-ViewPort-Units plug-in mentioned earlier is needed. This plugin will let you ignore the content of the content, the plugin will take care of it for you automatically. For example, the code processed by the plug-in:

The {padding: 3.2 vw; Margin: 3.2 vw auto; background-color: #eee; text-align: center; The font - size: 3.73333 vw; color: #333; content: "viewport-units-buggyfill; Padding: 3.2 vw; Margin: 3.2 vw auto; The font - size: 3.73333 vw "; }Copy the code

Postcss.config.js is the same as postcss-px-to-viewport:

plugins: {
  'postcss-viewport-units': {}
} 
Copy the code
3.2.2.2 side effects

After we use Viewport Units Buggyfill, as you can see, it’s taking up the Content property, so it’s causing more or less side effects. Such as the img element and pseudo-elements ::before or ::after.

For img, in some browsers, writing content will cause the image to not display properly, so you need to add style overwrite globally:

img { content: normal ! important; }Copy the code

Viewport Units Buggyfill does not apply to pseudo-elements such as ::before, even if vw Units are used, as in:

// before compiling. After {content: 'after '; display: block; width: 100px; height: 20px; background: green; } // after[data-v-469AF010] {content: "after content"; display: block; Width: 13.333 vw; Height: 2.667 vw; background: green; }Copy the code

3.3 Defects of the Viewport scheme

The adoption of VW for adaptation still has certain defects in dealing with some details. For example, when vw is used in the container and PX is used in the margin, the overall width will easily exceed 100vw, thus affecting the layout effect. Of course, we can also avoid, such as using padding instead of margin, using calc() ‘function and so on…

In addition, the conversion of PX to VW may not be completely divisible, so there is a certain pixel difference.

3.3.1 High power screen adaptation

Reading through the whole adaptation scheme, you will find that the Viewport adaptation scheme only uses VW to adapt to the size problem of screens of different sizes, but does not solve the problems of high-power screen display, such as the stereotypical 1PX problem, blurred picture display and other problems.

3.3.1.1 1 px

In fact, there are a lot of solutions on the Internet about 1PX to solve the problem of high-power screen display, such as The teacher in The Desert to talk about the Retina 1px solution, Zhou Junjun’s Retina real restore 1px frame solution, the method is always more than the problem.

Combined with the above solutions, I have also compiled several recommended solutions and tested their effects:

• Solve 1px problems by combining postCSs-write-SVG with border-image or background-image

The Border-image scheme works well, but has compatibility issues on some low-end models and ios devices. The main performance is that in some low-end Android models, such as Meilan Note1, when 4 frames are displayed, the bottom and right frames are missing; On the iPhone5s, iPhone6s and iPhone6s Plus, it doesn’t show up.

Another problem with border-image is that it cannot make rounded corners.

The background-image scheme can be better displayed on the above models, but a 2-pixel image is required in the background scheme, such as:

fineLine(color = #e8e8e8, position = bottom) if position == top || position == bottom background-repeat: repeat-x background-image: url(data:image/png; Base64, iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAAXNSR... hZcwAADsMAAA7DAcdvqGQAAAAQSURBVBhXY5g5c+Z/BhAAABRcAsvqBShzAAAAAElFTkSuQmCC) if position == top background-position: 0 0 else background-position: 0 100% else background-repeat: repeat-y background-image: url(data:image/png; Base64, iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAAXNSR... hZcwAADsMAAA7DAcdvqGQAAAAQSURBVBhXY5g5c+Z/BhAAABRcAsvqBShzAAAAAElFTkSuQmCC) if position == left background-position: 0 0 else background-position: 100% 0Copy the code

Of course, we can also use the postCSs-write-SVG capability to write a Base64 image that can draw the two types shown above:

@svg squareLR {width: 1px; height: 2px; @rect { fill: var(--color, black); width: 100%; height: 50%; } @svg squareTB {width: 2px; height: 1px; @rect { fill: var(--color, black); width: 50%; height: 100%; } // Mixin (color = #e8e8e8, color = #e8e8e8) position = bottom) if position == top || position == bottom background-repeat: repeat-x background-image: svg(squareLR param(--color color)) if position == top background-position: 0 0 else background-position: 0 100% else background-repeat: repeat-y background-image: svg(squareTB param(--color color)) if position == left background-position: 0 0 else background-position: 100% 0Copy the code

In addition, we also have a gradient background image scheme. In the gradient background image scheme, we only need to maintain a mixin code to achieve the desired effect:

bgLine($color = #efefef, $direction = all)
  background-repeat: no-repeat
  if $direction == all
    border: none
    padding: 1px
    background-image:
      -webkit-linear-gradient(top, transparent 50%, $color 50%),
      -webkit-linear-gradient(right, transparent 50%, $color 50%),
      -webkit-linear-gradient(bottom, transparent 50%, $color 50%),
      -webkit-linear-gradient(left, transparent 50%, $color 50%)
    background-image:
      linear-gradient(to top, transparent 50%, $color 50%),
      linear-gradient(to right, transparent 50%, $color 50%),
      linear-gradient(to bottom, transparent 50%, $color 50%),
      linear-gradient(to left,transparent 50%, $color 50%)
    background-size:
      100% 1px,
      1px 100%,
      100% 1px,
      1px 100%
    background-position:
      top center,
      right center,
      bottom center,
      left center
  else
    background-position: $direction center
    background-image: -webkit-linear-gradient($direction, transparent 50%, $color 50%);
    background-image: linear-gradient(to $direction, transparent 50%, $color 50%);
    if $direction == left || $direction == right
      background-size: 1px 100%
    if $direction == top || $direction == bottom
      background-size: 100% 1px
.test
    width 400px
  padding 24px
  margin 24px
  bgLine(red, all)  
Copy the code

However, the gradient background map scheme still has its disadvantages, such as unable to set the border rounded corners, the need to maintain the tedious gradient control code (although it may move once in ten thousand years) and other problems, but it is still worth trying the adaptation scheme.

• 0.5 px project

The 0.5px scheme is well supported after IOS8, and all the iPhone devices I can find clearly show the thin line we want. (However, for iPhone 6s Plus, iPhone X, iPhone Xs and other 3x IOS devices, it is not a real 1 physical pixel. It’s 1.5 physical pixels, but it doesn’t really matter).

After my test, after Android5.1, all devices are basically compatible with the normal display of 0.5px, but there are some devices that are lower than Android5.1 that can’t display properly, so we think this needs to use js code to do some hack. And the Flexible adaptation scheme is involved to do compatibility, which is simply a technological backward, can not bear.

Therefore, it is not recommended to use this strategy for 1px compatibility in a viewport adaptation project, given the overall balance of various scenarios.

• Pseudo-element + Transform Scale scheme

Compared with the above schemes, the pseudo-element + Transform Scale method is more concise, controllable and easy to understand, and this method also supports setting rounded corners. This adaptation scheme is adopted in most mobile terminal products of Tencent and JINGdong (Alibaba’s mobile terminal products, such as mobile version Taobao and mobile version Tmall, are not adapted to 1PX. Amazing! You’re thinking of it as an inevitable mistake.

The idea of the scheme is also very well understood, we will know at a glance:

border-1px($color = #ccc, $radius = 2PX, $direction = all)
  position: relative
  &::after
    content: ""
    pointer-events: none
    display: block
    position: absolute
    border-radius: $radius
    box-sizing border-box
    width 100%
    height 100%
    left: 0
    top: 0
    transform-origin: 0 0
    if $direction == all
      border: 1PX solid $color
    else
      border-{$direction}: 1PX solid $color
    @media only screen and (-webkit-min-device-pixel-ratio:2)
      width: 200%
      height: 200%
      border-radius: $radius * 2
      transform: scale(.5)
    @media only screen and (-webkit-min-device-pixel-ratio:3)
      width: 300%
      height: 300%
      border-radius: $radius * 3
      transform: scale(.333)
Copy the code
3.3.1.2 Picture blur problem

The problem of picture blurring under high magnification screen and its corresponding solution have been explained and introduced to you in simple and simple mobile adaptation, which is skipped here.

End, scatter flowers.

Four, parting message

At present, the mobile adaptation schemes that can be found in the walls are scattered, and some of the information is out of date or even distorted. The purpose of this article is to summarize and practice the mobile adaptation solutions that can be found on the Internet. It is also a learning process. Some of the ideas and ideas in these two articles or the implementation of the code may be more or less inadequate, welcome your criticism.

Five, the reference

• www.w3cplus.com/mobile/vw-l… • www.w3cplus.com/css/fix-1px… • www.w3cplus.com/css/vw-for-… • www.w3cplus.com/mobile/lib-… • blog.51cto.com/zhoulujun/2… • juejin. Cn/post / 684490… • www.cnblogs.com/sunLemon/p/… • segmentfault.com/q/101000001… • blog.noob6.com/2018/06/03/…