16
头图

I have been working on mobile pages for a while, so I will summarize several mobile adaptation schemes commonly used in my work.

Base

There are already a lot of basic knowledge summaries on the Internet, so I won't repeat them. For details, see

"What you need to know about mobile adaptation"

"Don't ask me about mobile adaptation again"

The concept that is easy to confuse is 视口

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

meta The viewport attribute in the label is the meaning of 视图

Viewport is divided into

  • layout viewport
  • visual viewport
  • ideal viewport

layout viewport

That is, the meaning of the <meta name="viewport" content="width=device-width"> in width attribute

All the styles we write in css are laid out relative to 布局视口

By default, the layout viewport of the mobile terminal is not the screen width, but generally between 768px ~ 1024px (980px in most cases)

It can be obtained through document.documentElement.clientWidth (according to width and initial-scale to determine)

visual viewport

The visual viewport refers to the area that the user sees through the device screen, which is equal to the window size of the current browser by default (when initial-scale is 1)

When the user zooms the browser, it does not change the size of the layout viewport, so the page layout remains the same, but zooming changes the size of the visual viewport

It can be obtained by window.innerWidth (will change with zoom)

Zoom in on the page, at this time window.innerWidth instead decreases (the page is enlarged, and you see less)

ideal viewport

Ideal viewport refers to the ideal size of a website on a mobile device, which is the screen size of the device

That is, the meaning of <meta name="viewport" content="width=device-width"> in device-width

Can be obtained through screen.width (constant, will not change)

initial-scale

<meta name="viewport" content="width=device-width, initial-scale=0.5">

According to the formula initial-scale = 理想视口宽度 / 视觉视口宽度

Assuming that the ideal viewport width is 414px (device-width), then set initial-scale to 0.5, then the visual viewport width is 414 / 0.5 = 818

If you get the value of document.documentElement.clientWidth (the layout viewport) at this time, you will find that it is not 414px but 818px

Conclusion: The layout viewport width is the maximum value of width and visual viewport width

Thinking questions:

<meta name="viewport" content="width=600, initial-scale=2">

Assuming the ideal viewport width is 414px (device-width), what is the value of document.documentElement.clientWidth (layout viewport)?

 视觉视口 = 414 / 2 = 207
布局视口 = Math.max(207, 600)
布局视口 = 600

Summarize

  • document.documentElement.clientWidth : Layout viewport, generally written in css as width=device-width
  • window.innerWidth : Visual viewport, page zoom will change this value in real time
  • screen.width : ideal viewport, page screen size (device independent pixels), which is device-width in css

Common adaptation schemes

To sum up in one sentence: The mobile terminal adaptation is the equal scaling of 屏幕宽度 :

Usually during our development, the mobile design draft we get is generally 750 * 1334 size (the iPhone6 device pixel is the standard design). Then if the width of the element measured on the 750px design draft is 100px , then under the screen with the width of 375px 79818f981a27a4d7fedaaf0e1b22d810---, the width of this element should be proportionally scaled to 50px .

So the difficulty of adaptation is: how to achieve proportional scaling of the page?

Rem scheme

The core of the scheme is: all elements that need dynamic layout, no longer use px fixed size, but use rem relative size

rem的大小是相对于根元素html的字体大小: htmlfont-size 100px,那么1rem is equal to 100px

Now we assume:

750pxhtmlfont-size 100px,也就是1rem 100px,那么200px宽度的.box element, it should be written as 2rem

 .box {
  /* 750px屏幕下,200px */
  width: 2rem;
}

So now:

375px Under the screen, we need .box to render the element as 100px

 .box {
  width: 2rem;
}

.box2rem ,因此,这时候我们就1rem 50px,也就是说, html The font-size is 50px

So at this point, we can get a formula:

(750) / (100) = (当前屏幕尺寸) / (当前屏幕1rem)

A mathematical transformation of this formula yields:

(当前屏幕1rem) = 100 * (当前屏幕尺寸) / 750

Translated into js language is

 document.documentElement.style.fontSize = 100 * (document.documentElement.clientWidth) / 750 + 'px';

optimize the code

 const PAGE_WIDTH = 750; // 设计稿的宽度 
const PAGE_FONT_SIZE = 100;// 设计稿1rem的大小

const setView = () => {
  //设置html标签的fontSize
  document.documentElement.style.fontSize = PAGE_FONT_SIZE * (document.documentElement.clientWidth) / PAGE_WIDTH + 'px';
}
window.onresize = setView; // 如果窗口大小发生改变,就触发 setView 事件
setView()

Considering the problem of font rendering on the Android side and the monitoring of page size changes, the final code is as follows:

 (function () {
  var timer = null;
  var PAGE_WIDTH = 750; // 设计稿的宽度 
  var PAGE_FONT_SIZE = 100;// 设计稿1rem的大小

  function onResize() {
    var e = PAGE_FONT_SIZE * document.documentElement.clientWidth / PAGE_WIDTH;
    document.documentElement.style.fontSize = e + 'px';
    // 二次计算缩放像素,解决移动端webkit字体缩放bug
    var realitySize = parseFloat(window.getComputedStyle(document.documentElement).fontSize);
    if (e !== realitySize) {
      e = e * e / realitySize;
      document.documentElement.style.fontSize = e + 'px';
    }
  }
  window.addEventListener('resize', function () {
    if (timer) clearTimeout(timer);
    timer = setTimeout(onResize, 100);
  });
  onResize();
})();

Note: We take 100px as the 1rem of the design draft, because it is convenient to calculate, such as 250px on the design draft, we can easily calculate it as 2.5rem .

Of course, we can also use 50px as the 1rem of the design draft. At this time, the 250px on the design draft should be written as 5rem .

In fact, we can also use the postcss-pxtorem or SCSS function to help us automatically convert the unit

 @function px2rem($px) {
  // 根元素字体为100px
  @return $px / 100 * 1rem;
}

.box {
  width: px2rem(200);
}

Through the Rem scheme, for elements that need to be dynamically scaled, we use rem relative units. For elements that do not need scaling, we can still use px fixed units.

However, under large-screen devices (such as ipad or pc), since our page is scaled proportionally, the elements of the page will be enlarged a lot at this time (the screen width is large, causing the root element font 1rem to become larger). But under the big screen, what we really want is for the user to see more content. At this time, we can use the media query method to limit the font of the root element, so as to prevent the problem of the element being too large under the big screen.

 @media screen and (min-width: 450px) {
  html {
    font-size: 50px !important;
  }
}

Or modify the logic of the js script

 const PAGE_WIDTH = 750; // 设计稿的宽度 
let PAGE_FONT_SIZE = 100;// 设计稿1rem的大小

const setView = () => {
  if (document.documentElement.clientWidth > 450) {
    // 大屏下减小根元素字体
    PAGE_FONT_SIZE = 50;
  }
  document.documentElement.style.fontSize = PAGE_FONT_SIZE * (document.documentElement.clientWidth) / PAGE_WIDTH + 'px';
}

VW solution

vw is a relative unit, 1vw means 1% of the screen width

In fact, our REM方案 is the simulation of VW方案 , before we have a formula:

(750) / (100) = (当前屏幕尺寸) / (当前屏幕1rem)

Change a conversion method:

(当前屏幕1rem) = (当前屏幕尺寸) / 7.5

The vw unit is actually:

(当前屏幕1vw) = (当前屏幕尺寸) / 100

Therefore, REM方案 is to use JS to divide the screen width into 7.5 parts, and the new vw unit in CSS3, the native implementation divides the screen width into 100 parts

So, in VW方案 , we don't need to use JS script anymore!

750px设计稿中, 1vw 7.5px (750 / 100),因此,在设计稿中, 200px的宽度, just because it is written as 26.667vw (200 / 7.5)

 .box {
  /* 750px屏幕下,200px */
  width: 26.667vw;
}

However, using vw conversion is not as convenient as rem . At this time, we can use postcss-px-to-viewport or SCSS function to help us automatically convert unit

 @function px2vw($px) {
  @return $px / 750 * 100vw;
}

.box {
  width: px2vw(200);
}

Similarly, under large-screen devices, due to the large screen width, the elements of the page will also be enlarged a lot (the screen width is large, and 1vw is also large). However, since vw is relative to the screen width, we cannot manually control the root font size of ---115aeb4faf912cf9ce5e9368331d09ef2 REM方案 as in html , which is also using VW方案 a disadvantage.

REM + VW solution

The advantage of REM方案 is that it can manually control the size of rem , preventing the page elements from scaling too much when the screen is too large, but the disadvantage is that you need to use JS . VW方案 just the opposite, no need to use JS but there is no way to manually control the size of vw .

In fact, we can combine the two:

 html {
  /* 750px 的设计图,1rem = 100px */
  font-size: calc(100 * 100vw / 750);
}

.box {
  /* 750px屏幕下,200px */
  width: 2rem;
}

For layout elements, we still use rem units. But for the font size of the root element, we don't need to use JS to dynamically calculate it

 100 * (document.documentElement.clientWidth) / 750

This js can be implemented directly using css

 calc(100 * 100vw / 750)

For large screen devices we use media queries

 @media screen and (min-width: 450px) {
  html {
    font-size: calc(50 * 100vw / 750);
  }
}

For more details vw+rem布局方案 see "Rem responsive typesetting and layout based on viewport units such as vw"

viewport scaling scheme

There is also a simpler and more crude method, that is, we set initial-scale

Our layout is completely based on the design draft 750px , and the layout element unit also uses px fixed unit (the layout viewport is written to 750px)

For the 375px width, we scale the entire page 0.5 :

<meta name="viewport" content="width=750, initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5, user-scalable=0">

 <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">
  <title>demo</title>
  <script>
    var clientWidth = document.documentElement.clientWidth;
    var viewport = document.querySelector('meta[name="viewport"]');
    var viewportWidth = 750;
    var viewportScale = clientWidth / viewportWidth;
    viewport.setAttribute('content', 'width=' + viewportWidth + ', initial-scale=' + viewportScale + ', minimum-scale=' + viewportScale  + ', maximum-scale=' + viewportScale + ', user-scalable=0');
  </script>
</head>
 .box {
  width: 200px;
}

Disadvantages of this scheme: The entire page is scaled, and there is no control over the elements that you don't want to scale.

Some marketing H5 pages on the market are built through visual drag and drop in the background. In order to adapt to screens of various sizes, this solution is the lowest cost implementation (this solution is used by Yiqixiu )

actual combat

Let's take the membership purchase of online B station as an example

Please use chrome developer tools to simulate mobile device viewing

The source code can be viewed directly by right-clicking. The code is not compressed. You can intuitively see the css adaptation of various schemes.

refer to


深红
2k 声望324 粉丝

萌豚