做挪动端页面有一段时间了,总结下工作中罕用的几种挪动端适配计划。
根底
网上曾经有十分多的基础知识总结,不再赘诉,详情能够见
《对于挪动端适配,你必须要晓得的》
《不要再问我挪动适配的问题了》
其中容易搞混的概念是 视口
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,viewport-fit=cover">
meta
标签中的 viewport
属性,就是 视图
的含意
视口分为
- 布局视口
- 视觉视口
- 现实视口
布局视口
也就是 <meta name="viewport" content="width=device-width">
中width
属性的含意
咱们在 css 中写的所有款式,就是绝对于 布局视口
进行布局的
默认状况下,挪动端的布局视口并不是屏幕宽度,而是个别在 768px ~ 1024px 间(大部分状况下 980px)
能够通过 document.documentElement.clientWidth
获取 (依据 width
和initial-scale
来确定)
视觉视口
视觉视口是指用户通过设施屏幕看到的区域,默认等于以后浏览器的窗口大小 (当initial-scale
为 1)
当用户对浏览器进行缩放时,不会扭转布局视口的大小,所以页面布局是不变的,然而 缩放会扭转觉视口的大小
能够通过 window.innerWidth
获取 (会随着缩放进行扭转)
放大页面,此时 window.innerWidth
反而减小 (页面放大,你看到的货色也变少了)
现实视口
现实视口是指网站在挪动设施中的现实大小,这个大小就是设施的屏幕大小
也就是 <meta name="viewport" content="width=device-width">
中device-width
的含意
能够通过 screen.width
获取 (常量,不会扭转)
initial-scale
<meta name="viewport" content="width=device-width, initial-scale=0.5">
依据公式initial-scale = 现实视口宽度 / 视觉视口宽度
假如现实视口宽度为 414px
(device-width),此时设置initial-scale
为 0.5,那么视觉视口宽度就是414 / 0.5 = 818
如果这时你获取 document.documentElement.clientWidth
(布局视口) 的值,会发现不是 414px
而是818px
论断: 布局视口宽度取的是 width 和视觉视口宽度的最大值
思考题:
<meta name="viewport" content="width=600, initial-scale=2">
假如现实视口宽度为 414px
(device-width),此时document.documentElement.clientWidth
(布局视口) 的值是多少?
视觉视口 = 414 / 2 = 207
布局视口 = Math.max(207, 600)
布局视口 = 600
总结
document.documentElement.clientWidth
: 布局视口,css 中个别写成width=device-width
window.innerWidth
: 视觉视口,页面缩放都会实时扭转该值screen.width
: 现实视口,页面屏幕大小(设施独立像素),也就是 css 中的device-width
常见适配计划
简略一句话概括:挪动端适配就是在进行 屏幕宽度
的等比例缩放:
平时咱们开发中,拿到的挪动端设计稿个别是 750 * 1334
尺寸大小(iPhone6 的设施像素为规范的设计图)。那如果在750px
设计稿上量出的元素宽度为 100px
,那么在375px
宽度的屏幕下,这个元素宽度就应该等比例缩放成50px
。
所以适配的难点是:如果实现页面的等比例缩放?
Rem 计划
该计划的外围就是:所有须要动静布局的元素,不再应用 px
固定尺寸,而是采纳 rem
绝对尺寸
rem
的大小是绝对于根元素 html
的字体大小:如果 html
的font-size
为 100px,那么 1rem
就等于 100px
当初咱们假设:
750px
屏幕下 html
的 font-size
为 100px,也就是 1rem
为 100px,那么 200px
宽度的 .box
元素,就应该写成2rem
.box {
/* 750px 屏幕下,200px */
width: 2rem;
}
那么当初:
375px
屏幕下,咱们须要 .box
元素渲染成100px
.box {width: 2rem;}
因为 .box
的宽度依然是2rem
,因而,这时候咱们就须要1rem
为 50px,也就是说,此时 html
的font-size
为 50px
于是此时,咱们能够得出一个公式:
(750) / (100) = (以后屏幕尺寸) / (以后屏幕 1rem)
把这个公式进行一次数学转换就能失去:
(以后屏幕 1rem) = 100 * (以后屏幕尺寸) / 750
翻译成 js 语言就是
document.documentElement.style.fontSize = 100 * (document.documentElement.clientWidth) / 750 + 'px';
将代码优化一下
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()
思考到 Andorid 端字体渲染的问题以及页面大小变动的监听,最终的代码如下:
(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();})();
留神的是:咱们取 100px
作为设计稿的 1rem,是因为不便计算,比方设计稿上量出250px
,咱们就能够很容易的计算出为2.5rem
。
咱们当然也能够把 50px
作为设计稿的 1rem,这时设计稿上的250px
,就要写成5rem
。
其实咱们也能够借助于 postcss-pxtorem 或者 SCSS
函数来帮咱们主动转换单位
@function px2rem($px) {
// 根元素字体为 100px
@return $px / 100 * 1rem;
}
.box {width: px2rem(200);
}
通过 Rem 计划,须要动静缩放的元素,咱们应用 rem
绝对单位,不须要缩放的元素,咱们依然能够应用 px
固定单位。
不过在大屏设施下(例如 ipad 或者 pc 端),因为咱们的页面是等比例缩放,这时候页面的元素会被放大很多(屏幕宽度大,导致根元素字体 1rem 也变大)。然而在大屏下,咱们真正心愿的是用户看到更多的内容,这时候咱们能够应用媒体查问的形式来限度根元素的字体,从而避免在大屏下元素过大的问题。
@media screen and (min-width: 450px) {
html {font-size: 50px !important;}
}
或者批改 js 脚本的逻辑
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 计划
vw 是绝对单位,1vw 示意屏幕宽度的 1%
其实咱们的 REM 计划
就是 VW 计划
的模仿,之前咱们有一个公式:
(750) / (100) = (以后屏幕尺寸) / (以后屏幕 1rem)
换一个转换形式:
(以后屏幕 1rem) = (以后屏幕尺寸) / 7.5
而 vw 单位其实就是:
(以后屏幕 1vw) = (以后屏幕尺寸) / 100
因而,REM 计划
就是用 JS 把屏幕宽度分成了 7.5 份,而 CSS3 中新增的 vw
单位,原生实现了把屏幕宽度分成了 100 份
所以,在 VW 计划
中,咱们不再须要应用 JS 脚本了!
750px
设计稿中,1vw
等于 7.5px
(750 / 100),因而,在设计稿中,量出200px
的宽度,就因为写成26.667vw
(200 / 7.5)
.box {
/* 750px 屏幕下,200px */
width: 26.667vw;
}
不过应用 vw
换算,并不像 rem
那么不便,这时候咱们能够借助 postcss-px-to-viewport 或者 SCSS
函数来帮咱们主动转换单位
@function px2vw($px) {@return $px / 750 * 100vw;}
.box {width: px2vw(200);
}
同样,在大屏设施下,因为屏幕宽度大,所以页面的元素同样会放大很多 (屏幕宽度大,1vw 也很大)。然而因为vw
是绝对屏幕宽度的,所以咱们不能像 REM 计划
中一样,手动管制 html
的根字体大小,这也是应用 VW 计划
的一个毛病。
REM + VW 计划
REM 计划
的劣势是能够手动管制 rem
的大小,避免屏幕太大时,页面元素也缩放很大,然而毛病就是须要应用 JS
。VW 计划
刚好相同,无需应用 JS
然而无奈手动管制 vw
的大小。
其实咱们能够把两者联合:
html {
/* 750px 的设计图,1rem = 100px */
font-size: calc(100 * 100vw / 750);
}
.box {
/* 750px 屏幕下,200px */
width: 2rem;
}
对于布局元素,咱们依然应用 rem
单位。然而对于根元素的字体大小,咱们不须要应用 JS 来动静计算了
100 * (document.documentElement.clientWidth) / 750
这段 js 能够间接应用 css 来实现
calc(100 * 100vw / 750)
对于大屏设施,咱们应用媒体查问
@media screen and (min-width: 450px) {
html {font-size: calc(50 * 100vw / 750);
}
}
更具体的vw+rem 布局计划
能够见《基于 vw 等 viewport 视区单位配合 rem 响应式排版和布局》
viewport 缩放计划
还有一种更简略粗犷的办法,就是咱们设置initial-scale
咱们的布局齐全基于设计稿 750px
,布局元素单位也应用px
固定单位 (布局视口写死 750px)
对于 375px
宽度,咱们就将整个页面缩放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;}
此计划的毛病: 整个页面都被缩放了,对于不想缩放的元素无法控制。
市面上一些营销 H5 页面,因为是通过后盾可视化拖拽搭建进去的,为了适配各种尺寸的屏幕,该计划是老本最低的实现(易企秀就是应用这种计划)
实战
咱们拿线上 B 站的会员购作为示例
- rem 计划
- vw 计划
- rem+vw 计划
- viewport 计划
请应用 chrome 开发者工具模仿挪动端设施查看
源码间接右键查看即可,代码没有通过压缩,能够很直观的看到各种计划的 css 适配写法
参考
- 挪动端适配有哪几种计划?
- 不要再问我挪动适配的问题了
- 对于挪动端适配,你必须要晓得的
- 基于 vw 等 viewport 视区单位配合 rem 响应式排版和布局