做挪动端页面有一段时间了,总结下工作中罕用的几种挪动端适配计划。

根底

网上曾经有十分多的基础知识总结,不再赘诉,详情能够见

《对于挪动端适配,你必须要晓得的》

《不要再问我挪动适配的问题了》

其中容易搞混的概念是视口

<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获取 (依据widthinitial-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的字体大小:如果htmlfont-size为100px,那么1rem就等于100px

当初咱们假设:

750px 屏幕下 htmlfont-size为100px,也就是1rem为100px,那么200px宽度的.box元素,就应该写成2rem

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

那么当初:

375px 屏幕下,咱们须要.box元素渲染成100px

.box {  width: 2rem;}

因为.box 的宽度依然是2rem,因而,这时候咱们就须要1rem为50px,也就是说,此时htmlfont-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的大小,避免屏幕太大时,页面元素也缩放很大,然而毛病就是须要应用JSVW计划刚好相同,无需应用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响应式排版和布局