茴字的四种写法—移动适配方案的进化

话说我刚工做的时候,就开始用rem了,过了没多久,接触到了flexible,系统化且支持iOS的retina屏迅速征服了我,最近又看到了大漠大神的vw。因此本文想完成一篇一站式的文章,能够系统的了解前端适配的演进。闲话少叙,立刻开始。

1. 什么是前端适配

从UI展示层面上:
咱们指望不一样尺寸的设备,页面能够自适应的展现或者进行等比缩放,从而在不一样的尺寸的设备下看起来协调或者差很少css

从代码实现层面上:
咱们但愿前端适配能够用用尽量简洁的代码来实现。最好一套代码实现兼容全部设备,而不是对每一个或每种设备都写一套方案,不是次次都选用最无奈的方案(Android和iOS分开编写)。html

2. 关键字

若是你了解这些关键字,那么这段大能够跳过,若是后面遇到了问题,感受有些疑惑,也能够再回来查阅。前端

2.1 Viewport/视口

通俗的讲,移动设备上的viewport就是设备的屏幕上能用来显示咱们的网页的那一块区域[1],但不必定是咱们可见的区域。具体来讲,分为如下三种。vue

2.1.1 Visual Viewport

Visual Viewport: 可见视口。就是移动设备上能够被咱们看见的部分。宽度在移动端经过window.innerWidth得到(仅限移动端,PC上哪怕是chrome模拟也会有不一样的结果)。

图片描述

2.2.2 Layout Viewport

Layout Viewport: 布局视口。

图片描述

若是把PC上的页面放到移动端,以iphone8为例,若是只展现为可见视口的宽度(375px),那么页面会被压缩的特别窄而显示错乱,因此移动浏览器就决定默认状况下把viewport设为一个较宽的值,好比980px,这样的话即便是那些为桌面设计的网站也能在移动浏览器上正常显示了。[1]android

而事实上,咱们通常看不到如上图这样出现横向滚动条的界面;在手机上访问页面时,每每是下图的样子:git

图片描述

这是因为页面body宽度设置了100%而没有指定一个具体的宽度致使的,从而使页面被等比缩放了。因为用户能够缩放,因此还算能正常浏览。github

2.2.3 Ideal Viewport

Ideal Viewport:理想视口,其实就是设备的可见区域,和可见视口一致。

设置Ideal Viewport的好处是,只要按照Ideal Viewport来设计样式稿,用户就不用能最完美的查看网站的内容——既不用左右滑动,也不用放大缩小。web

设置理想视口:chrome

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">

这段代码的意思是将布局视口的宽度设置为设备宽度,初始缩放比例为1,最大缩放比例为1,用户不能缩放。浏览器

2.2 像素

2.2.1 物理像素

物理像素:一个物理像素是显示器(手机屏幕)上最小的物理显示单元,在操做系统的调度下,每个设备像素都有本身的颜色值和亮度值。[2]

2.2.2 设备独立像素

设备独立像素:又称为CSS像素,就是咱们平常代码中使用的像素。浏览器内的一切长度都是以CSS像素为单位的,CSS像素的单位是px。

2.2.3 设备像素比

设备像素比(简称dpr)定义了物理像素和设备独立像素的对应关系。好比说对于iOS的retina屏,一个设备独立像素就对应着4个物理像素。这样的设计可使画面更加清晰锐利,以下图:
图片描述

3. 业界的解决方案

OK,LongLongAgo的前缀以后,终于到了正题。回到咱们最开始的初心:咱们只是想要经过一套代码,实现一个能够在不一样页面尺寸上展现差很少的页面。在这一块,如今主要有三种方案。

3.1 Rem的解决方案

DPR一致时,px在不一样的屏幕尺寸上会展现为定宽,这就致使咱们的页面可能会出现滚动条或者占不满的状况。而经过rem来设置div的宽高,能够保证页面能够经过调整html的font-size来总体放大或者缩小,从而达到无论屏幕宽度是多少,页面都能完美展现的效果。

例如,针对750*1334的设计稿:

<meta name="viewport" content="initial-scale=1,maximum-scale=1, minimum-scale=1">
<script>
    document.documentElement.style.fontSize = window.innerWidth / 7.5 + 'px';
</script>

这样,全部的设备的宽度都是7.5rem,只须要把设计稿上的px值统一除以100,就能够获得相应的rem值了。

网易也采用的这种方法。

3.2 Flexible.js

Flexible是阿里团队开发的前端适配方案,也是用的rem的方法。那么第一种方法其实已经能解决前端适配问题了,为何阿里还要开发一个Flexible呢?

在第一种方法中,dpr=1时没有任何问题,可是在dpr=2或者更高的手机屏幕上,由于物理像素的增长,存在小于1px的显示空间。若是采用第一种方法,由于它统一对scale设置为1,那么咱们假如想要实现0.5px, 就只能经过transform的方式。若是有多个这样的样式,代码就会变得很麻烦。

.scale{
    position: relative;
}
.scale:after{
    content:"";
    position: absolute;
    bottom:0px;
    left:0px;
    right:0px;
    border-bottom:1px solid #ddd;
    -webkit-transform:scaleY(.5);
    -webkit-transform-origin:0 0;
}

所以,阿里的flexible方案充分考虑了这种状况,动态的设置了fontsize和scale, 从而使得CSS中的1px等于物理像素中的1px,在IOS下获得最清晰的体验。

if (!dpr && !scale) {
    var isAndroid = win.navigator.appVersion.match(/android/gi);
    var isIPhone = win.navigator.appVersion.match(/iphone/gi);
    var devicePixelRatio = win.devicePixelRatio;
    if (isIPhone) {
        // iOS下,对于2和3的屏,用2倍的方案,其他的用1倍方案
        if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {                
            dpr = 3;
        } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
            dpr = 2;
        } else {
            dpr = 1;
        }
    } else {
        // 其余设备下,仍旧使用1倍的方案
        dpr = 1;
    }
    scale = 1 / dpr;
}

最终在iphone8下页面的header被设置为:
<meta name="viewport" content="initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no">

具体的你们能够看《使用Flexible实现手淘H5页面的终端适配

另外须要指出的一点是:Flexible将页面分红了100份,页面的宽度是10rem,对于750的设计稿,咱们须要用相应的px数除以75来获得。手动计算是愚蠢的,不一样的编译器均可如下载pix2rem插件(能够直接写px而后自动转换为相应的rem值),直接使用sass或者postcss打包也能达到一样的功能。

总结一下上面两种rem方法,主要思想为:

  • 根据dpr的值来修改html的font-size,从而使用rem实现等比缩放
  • 根据dpr的值来修改viewport实现1px的线

可是Flexible也有它的局限性,具体表现为:

  • 不能与响应式布局兼容
  • 对Android没有作处理,致使1px和backgroudImage还要额外作处理的问题[4]

因此咱们有了第三种解决方案——vw。

3.3 vw

vw是基于Viewport视窗的长度单位,在CSS3中和Viewport相关的单位有四个,分别为vw、vh、vmin和vmax。

  • vw: 是Viewport's width的简写,1vw等于window.innerWidth的1%
  • vh:和vw相似,是Viewport's height的简写,1vh等于window.innerHeihgt的1%
  • vmin: vmin的值是当前vw和vh中较小的值
  • vmax: vmax的值是当前vw和vh中较大的值

其实vw的方案的写法和flexible方案的写法一致——由于flexible其实就是用hack的手段模拟了vw的实现而已。

具体写法:针对750px的设计稿,将相应的px值除以7.5就是vw的值。

由于此方法不会改变可见视口的宽度,因此能够和media query通用了,另外,也支持了Android上高分辨率屏的展现。

尽管在某些Android机型上还存在兼容问题,咱们也可使用Viewport Units Buggyfill,具体见《如何在Vue项目中使用vw实现移动端适配

总结

正如大漠所说,flexible模拟vw的时代已通过去,真正的酋长vw已经归来

参考文档:

  1. 移动前端开发之viewport的深刻理解
  2. 移动端高清、多屏适配方案
  3. 再聊移动端页面的适配
  4. 基于淘宝弹性布局方案lib-flexible的问题研究
  5. 如何在Vue项目中使用vw实现移动端适配
相关文章
相关标签/搜索