如何开发一个移动web UI组件库:适配篇

@youngwind 2016-08-13 02:50:58发表于 youngwind/blog Vue移动H5

前言

屏幕尺寸适配一直是移动web开发的大问题,在进行UI组件库的开发的时候,必然绕不过这个问题。不过,我想跳出组件库的范畴,从更广泛的角度谈一谈移动端屏幕尺寸适配。

流行多年的rem

基于rem的适配方案在数年前就已经兴起,并且一直沿用至今,较为系统的代表是淘宝的flexible
关于如何使用这套体系,前人之述备矣。我就不赘述了。 下面重点说一下我的使用体会。

适配与dpr无关

问题:在flexible体系当中引入dpr的概念,但是却又在代码中强制指定所有安卓的dpr都是1。如下代码片段。

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;
    }

为什么要这么做?
官方的说法是:当时安卓很多机型的dpr都是假的。参考这里

然而,我们从这儿也可以发现:即便设置的dpr与安卓机真实的dpr不同,但是适配方案仍然能正常工作。也就是说,设置的dpr与真实的dpr是否相等其实根本不影响此适配方案
我们还可以从源代码的另一方面来佐证这个结论。

 // line 51
scale = 1 / dpr;   

// line 58
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');  

// line 68
var width = docEl.getBoundingClientRect().width;  // 这个width是会根据scale按倍数缩放的
var rem = width / 10;
 docEl.style.fontSize = rem + 'px';

发现没?其实本质上是先通过根元素的fontSize放大dpr倍,然后再通过viewport的scale缩小dpr倍,仅此而已。

既然dpr不影响适配,那么方案中为什么要引入它?
答案:是因为要同时解决“1px边框问题”和“高清图片问题”了,具体的可以参考这篇文章

rem的弊端

flexible改变根元素的fontSize和viewport的scale,相当于js里面的改变了两个全局变量。那么我页面当中的所有其他元素都必须按照这个基准进行,这样我们在嵌入第三方内容的时候就会很不方便。比如:

  1. 地图问题 amfe/lib-flexible#54
  2. 我们引入了一个第三方的UI组件库(或者我们自己写一个UI组件库),要是不遵照这个体系来就完蛋了。(目前我写的那个UI组件库也是强依赖于flexible)

天猫与淘宝

既然rem有一些问题,那么有替代方案吗?flexbox布局很早就出来了,迟迟不能广泛使用还是因为兼容性的问题。但是天猫已经率先使用了,可以参考如何看待手机天猫首页改用 flex 布局?与手机淘宝首页的 Rem 方案相比有何优缺点?
在回答”flexbox能否提到rem“这个问题之前,我仔细对比天猫的首页和淘宝的首页,会发现一些有趣的东西。
下图分别是iPhone5s和iPhone6p的对比图。(竖着排版对比不方便,建议把图片下载下来切换对比)
淘宝5s
淘宝6p
天猫5s
天猫6p

我们可以观察到一个现象:
对于天猫而言,6p比5s显示的内容显然要更多。对于淘宝而言,6p与5s显示的内容几乎是一样多。
为什么会这样呢?按理说这两个网站肯定都做到了适配的啊?

适配的标准

问题的答案在于:**适配的标准不同。**对于淘宝而言,当屏幕变大的时候,适配的效果是”按照比例放大“,元素的宽和高都按倍数增加,所以看到的内容一样多。对于天猫而言,当屏幕变大的时候,适配的效果不是”按照比例放大“,而是高度不变,宽度变化。所以可以看到更多的内容。两个标准都是可以接受的。如果是要做到第一个标准,则需要采取flexible方案,如果要做到第二个标准,则需要采取flexbox方案。

适配的原则

以前我们讨论响应式的标准的时候常常是这样考虑的:”当一个div在小屏幕是这么大的时候,那么在大屏幕下应该是多大呢?“但是,其实这种考虑是片面的。因为真实的需要考虑适配的场景往往不仅仅是div那么简单。比如这个div里面可能是文字,也可能是按钮,也可能是图片等等。我觉得有一个规则非常的好。

文字流式,控件弹性,图片等比缩放。
适配原则

出处:http://www.ui001.com/article/123.html

举例:看刚才天猫的那个例子,中间那”十大金刚“,当屏幕变大的时候,它们只不过是相互之间的距离变大的,”金刚“入口本身的大小是没有发生改变的,这就是所谓的”控件弹性“。而淘宝则不是。上面的图片已经标注出了这种差异。

尾声

说来说去,还是那句话:”生命不息,折腾不止“。关于移动端适配,以后可能有更好的解决方案,但是可以预见的是,依旧会有新的问题冒出来。最近刚刚看了张鑫旭大大写的文章基于vw等viewport视区相对单位的响应式排版和布局,也许会成为未来流行的适配方案。