用大白话理解 flexible.js 1.0 移动端可伸缩适配方案

flexible.js 是手淘的布局适配库

前置的一些概念,可以看这两个文章:
使用Flexible实现手淘H5页面的终端适配
flexible 详解

因为之前接触了很多适配方案,大同小异,导致对rem适配方案始终无法形成有效的记忆。
这次,直接拿手淘的flexiable 作为标准方案,理解它,作为自己的适配方案。

看flexible关键代码:

找到一个设备的dpr

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

devicePixelRatio

该 Window 属性 devicePixelRatio 能够返回当前显示设备的物理像素分辨率与 CSS 像素分辨率的比率。此值也可以解释为像素大小的比率:
一个 CSS 像素的大小与一个物理像素的大小的比值。简单地说,这告诉浏览器应该使用多少个屏幕的实际像素来绘制单个 CSS 像素。

找到一个设备的css宽度(逻辑宽度,视口)

var width = docEl.getBoundingClientRect().width;

getBoundingClientRect

Element.getBoundingClientRect() 方法返回元素的大小及其相对于视口的位置。
如果是标准盒子模型,元素的尺寸等于width/height + padding + border-width
如果box-sizing: border-box,元素的的尺寸等于 width/height
用大白话理解 flexible.js 1.0 移动端可伸缩适配方案_第1张图片

找到一个设备的 rem

function refreshRem(){
        var width = docEl.getBoundingClientRect().width;
        if (width / dpr > 540) {
            width = 540 * dpr;
        }
        var rem = width / 10;
        docEl.style.fontSize = rem + 'px';
        flexible.rem = win.rem = rem;
    }

width / dpr
得到 1 个 dpr 的物理像素
540
限定,540*dpr 是最大的适配宽度,避免图片模糊;
var rem = width / 10;
把屏幕宽度 分为 10 份,1份1rem;(直接分100份,有1rem 小于12px 的风险)

设计约定俗成的一个前提

设计师一般都是以iphone6 为基础设计UI,iphone6 css width 是375px;设计稿为两倍图 750px;
(设计师为了出高清图,一般稿子都会出到符合物理像素的大小)

开发一份基于iphone6的UI布局实现

假如设计稿上有个div ,测量是 100*100
因为设计稿总宽度是750px, 分为10分, 每份就是1rem,即是75px; 100/75 = 1.3333 rem
代码就是:

div{
    width: 1.3333rem;
    height: 1.3333rem;
}

这是直接通过rem单位实现了设计稿的尺寸。如果直接放到iphone6 上,会发现,页面比屏幕大了一倍;因为设计稿是按照逻辑像素1:1出的,此时 1px = 1pt。而iphone6 的css是 1px = 2pt 所以我们还需要对页面缩放 scale

找到一个设备的 scale ,屏幕缩放比

dpr = window.devicePixelRatio
dpr = 物理像素 / 逻辑像素

scale = 1 / dpr;
   

所有设备的设计稿实现都缩小为 1个逻辑像素屏幕 大小;
这时候,UI 可以在iphone6 的屏幕上完美呈现;

其它机型怎么适配?

你已经得到一份基于iphone6 的 rem 单位实现;
因为rem 是相对单位,并且是约定把1屏宽度分为10份来实现的rem;换句话说就是,所有1rem为1屏的十分之一的手机,显示这套实现都不会布局错乱。所以这套实现是可以直接复用的。
要复用,需要满足你的html 设置满足一些条件

复用条件

1:把屏幕分为10份,每一份 表示1rem,设置 html: font-size = (width/10) px
2:把视口缩放为 (1/dpr)

大白话

大白话讲,我们目的是为了 把一份基于rem的实现 放到所有的手机屏幕上,让他们都显示一样,只是等比缩放的差异而已;
通过viewpoint 的 scale 属性,我们可以把html 像缩放图片一样,缩放到刚刚好100%屏幕。
通过设置1rem 对应十分之一屏幕,我们可以复用这份布局实现。

后续

因为viewpoint 再浏览器的完善,flexible.js 已经推出2.0版本;
2.0

看了下关键源码:

 // adjust body font size
  function setBodyFontSize () {
    if (document.body) {
      document.body.style.fontSize = (12 * dpr) + 'px'
    }
    else {
      document.addEventListener('DOMContentLoaded', setBodyFontSize)
    }
  }
  setBodyFontSize();

  // set 1rem = viewWidth / 10
  function setRemUnit () {
    var rem = docEl.clientWidth / 10
    docEl.style.fontSize = rem + 'px'
  }

  setRemUnit()

  // reset rem unit on page resize
  window.addEventListener('resize', setRemUnit)
  window.addEventListener('pageshow', function (e) {
    if (e.persisted) {
      setRemUnit()
    }
  })

大概思想还是把1屏分为 10等份;不过再使用rem 作为单位了,而是使用vw
vw 天然就是把1屏幕 = 100 vw;
然后上面的那套iphone6实现,把所有rem 改为vw 就可以了。

你可能感兴趣的:(html5webapp)