移动端适配基础总结

说到移动端适配,首先咱们须要先搞清楚一些基础知识,因此本文路线是先了解像素,dpr,视口等基础知识,而后再整理出移动端适配方案。php

基础知识

像素

像素其实分为两种,分别是物理像素和CSS像素html

  1. 物理像素(设备像素)
    物理像素,顾名思义,显示屏是由一个个物理像素点组成的,经过控制每一个像素点的颜色,使屏幕显示出不一样的图像,屏幕从工厂出来那天起,它上面的物理像素点就固定不变了,单位pt。
    一般咱们看一些电子设备的参数,好比分辨率用的就是物理像素。它配合屏幕尺寸(注意:屏幕尺寸一般是说屏幕的对角线长度),能够计算出PPI(每英寸像素取值),即每一英寸物理像素数量。PPI越高,说明屏幕能提供更多细节。
    ppi计算公式
  2. CSS像素
    CSS和js使用的抽象单位,浏览器内的一切长度都是以CSS像素为单位的,CSS像素的单位是px。
  3. 物理像素和CSS像素之间的关系(dppx,DPR)
    在非高清屏及未缩放的状态下,一个CSS像素等于一个物理像素,而在一些PPI很是高的屏幕(例如苹果的视网膜屏幕)上,若是还让一个CSS像素等于一个物理像素,就会致使网页上的元素变得很是小,所以高PPI屏下,一般一个CSS像素等于两个甚至三个物理像素(由浏览器厂商决定,不一样浏览器设定的值可能不一样)。若是一个CSS像素占用n个物理像素,那么咱们就说此时的dppx(dots per px)为n。
    因此,咱们能够用dppx描述物理像素和CSS像素之间的关系。dppx除了和PPI有关,也和当前缩放状态有关,举个例子,在非高清屏下,若是没缩放,一个CSS像素占用一个物理像素,此时是1dppx,但若是将页面放大到200%,此时一个CSS像素等于两个物理像素,即2dppx。
    DPR(设备像素比,devicePixelRatio)描述的是未缩放状态下,物理像素和CSS像素的初始比例关系,计算方法以下图。
    DPR计算公式
    DPR由浏览器厂商决定,咱们没法修改,但能够经过window.devicePixelRatio读取DPR。
    可能有人疑问DPR和dppx到底啥关系,咱们能够认为DPR描述的是未缩放状态,而dppx能够描述任意时刻的状态,未缩放状态下的dppx和DPR相等,当有缩放操做时,此时的物理像素和CSS像素的比例关系就只能用dppx描述了。

视口(viewport)

视口也叫做初始包含块,之因此叫这个名字,是由于它包含了元素,它的宽度是全部CSS百分比宽度推算的根源。
在桌面浏览器,视口的宽度等同于浏览器窗口的宽度,高度即为浏览器窗口的高度。但移动端就有点复杂了,移动端的视口分为布局视口和视觉视口。git

  1. 布局视口(layout viewport)
    说布局视口以前,咱们先说一下桌面端的页面放到移动端浏览器后出现的问题:因为早期的页面不少采用固定宽度的布局,致使放在移动端的小窗口下出现横向的滚动条,不便于用户查看,因此浏览器厂商研究出了布局视口。布局视口的宽度通常在768px~1024px(由浏览器厂商设置),常见宽度980px,虽然设置了很大的宽度,但在没有手动设置宽度的状况下,布局视口仍会容纳在一屏里(说白了,就是把980px的东西装在320px的屏幕里),这样,浏览器会避免出现横向滚动条。
设置布局视口宽度:<meta name="viewport" content="width=640">
获取布局视口宽度:document.documentElement.clientWidth

布局视口除了和meta设置的width有关,还和scale有关,scale后面会说。github

  1. 视觉视口(visual viewport)
    用户正在看到的网页的区域,大小是屏幕中CSS像素的数量。
获取视口宽度:window.innerWidth/Height

初始状态下,通常视觉视口会等于布局视口。web

  1. 理想视口
    当布局视口的宽度达到理想状态时,就是理想视口,理想视口中的页面有最理想的宽度,用户进入页面不用缩放。
实现方法:<meta name="viewport" content="width=device-width">(即设置布局视口宽度为设备宽度)

缩放(scale)

原理:能够理解为修改dppx,举个例子,假设一屏幕DPR为2,即1px对应2pt,若是这个时候,咱们设置scale=0.5,那么dppx就会从2变成1,即1px对应1pt。因此,经过缩放咱们能够调整本身所能控制的最小物理像素粒度。
缩放会影响布局视口的大小,由于浏览器会尽可能让布局视口铺满屏幕,因此当咱们设置scale=0.5时,布局视口的宽度会自动变为原来的两倍。
具体以下图所示。
选择的移动调试设备浏览器

<meta name="viewport" content="width=device-width,initial-scale=1.0">
    <script>
        console.log(document.documentElement.clientWidth);   //结果为375
    </script>
<meta name="viewport" content="width=device-width,initial-scale=0.5">
    <script>
        console.log(document.documentElement.clientWidth);   //结果为750
    </script>

可能有人会问,scale的初始值是多少?其实这取决于viewport的宽度,由于浏览器会尽可能让布局视口铺满全屏,因此浏览器会根据布局视口的大小动态调整scale的初始值大小,从而使布局视口铺满全屏。
使用缩放的好处:对于DPR为2或更高的屏幕,若是不作缩放操做,咱们所能控制的最小物理像素粒度是2pt或更多物理像素,这样带来了两个问题。wordpress

  • 若是设计图上某个边框标识的大小是1px,那说明设计师想让这个边框在任何屏幕上都是1像素,在普通屏幕上,不会有问题,但在retina这种高清屏上,当咱们用1px修饰border时,实际上会有2pt渲染为border,致使border看上去比普通屏的border宽。
<style>
#log {
    border: 1px solid black;
}
</style>
<div id="log"></div>

scale=0.5

scale=1.0

  • 对于高清屏,若是咱们控制像素的粒度仍是2pt或3pt,实际上咱们并无充分利用高清屏展示细节的能力。

解决这两个问题的方法就是缩放,咱们把scale设置为1/dpr。布局

meta.setAttribute('content', 'initial-scale=' + 1/dpr + ', maximum-scale=' + 1/dpr + ', minimum-scale=' + 1/dpr + ', user-scalable=no');

这样1px就对应1pt,咱们就能够解决1px border问题和图片的高清问题了。flex

适配方案

  1. 固定高度,宽度自适应
    即垂直方向使用固定大小,水平方向使用百分比,flex。
<meta name="viewport" content="width=device-width,initial-scale=1">

适合场景:比较适合列表式的结构。优化

  1. 固定宽度,viewport缩放
    开发页面时彻底按照和设计图1:1的比例开发,设计图,页面,视口宽度使用同一个宽度,单位使用px便可,因为浏览器会尽可能将布局视口铺满全屏,因此浏览器会自动帮助咱们缩放。举个例子,假设设计图是640px宽,那咱们这样设置。
<meta name="viewport" content="width=640">

这个时候会发现,浏览器会帮助咱们将页面铺满全屏,并且这是绝对的等比例缩放。图片、文字等等全部元素都被缩放在手机屏幕中。

  1. rem作宽度,viewport缩放
    根据屏幕宽度设定rem值,须要适配的元素都使用rem为单位,不须要适配的元素仍是使用 px 为单位。
    总共分两步:

    • 动态设置font-size
    document.getElementsByTagName('html')[0].style.fontSize = window.innerWidth / 10 + 'px';
    • 缩放viewport
    meta.setAttribute('content', 'initial-scale=' + 1/dpr + ', maximum-scale=' + 1/dpr + ', minimum-scale=' + 1/dpr + ', user-scalable=no');

第二步是对页面适配的优化,修改scale是为了解决前面说到的1px border问题。
淘宝的Flexible使用的就是这种方案,并且它加了data-dpr属性,这样咱们就能够根据不一样的DPR设置不一样的样式。

方案总结

方案一比较适合列表这种比较固定的结构,方案二适合的场景比较多,并且实现简单,但须要注意它会将页面的全部元素都缩放,方案三适合的场景是页面内有些元素须要适配,有些元素不须要适配。整体来说,方案二和方案三是比较经常使用的方式。

参考文献:

https://www.zybuluo.com/gongzhen/note/170557
郑航的知乎回答https://www.zhihu.com/question/35221839
https://github.com/amfe/article/issues/17
https://github.com/riskers/blog/issues/18
https://riskers.github.io/share/share/flexible.htm#1
https://github.com/riskers/blog/issues/17
https://github.com/amfe/lib-flexible
http://www.html-js.com/article/2402
http://www.alloyteam.com/2016/03/mobile-web-adaptation-tool-rem/
https://www.nihaoshijie.com.cn/index.php/archives/593
http://www.zhangxinxu.com/wordpress/2012/08/window-devicepixelratio/

相关文章
相关标签/搜索