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 aswidth=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 isdevice-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
的字体大小: html
的font-size
100px,那么1rem
is equal to 100px
Now we assume:
750px
下html
的font-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;
}
.box
的2rem
,因此,这时候我们就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.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。