手淘rem的适配方案详解


手淘rem的适配方案详解

什么是rem?

CSS3新增的一个相对单位rem(root em,根em)。rem是相对于根节点(或者是html节点)。如果根节点设置了font-size:10px;那么font-size:1.5rem;字体大小等于15px。

想想看,因为rem是一个相对单位,那么只要根节点的font-size属性随着屏幕自适应,那么下面通过rem设置的单位便可以达到自适应的目的!
当我们拿到设计稿的时候,主要会将视觉稿分成100份(主要为了以后能更好的兼容vh和vw),而每一份被称为一个单位a。同时1rem单位被认定为10a。就相当于1rem可以定为宽度为屏幕的10%。那么针对一个750px宽的设计稿,我们可以算出:

1a   = 7.5px
1rem = 75px 

那么这个设计稿也就被分成了10rem份。此时淘宝开源库lib-flexible会为根节点的html和body元素设置一个data-dprfont-size两个属性。其中dpr在IOS内会根据不同型号的机器动态的计算生成,大多数机型的data-dpr=2但是对于安卓来说,由于其机型特别复杂多样,dpr会全部设置成1。
font-size = 1rem,对于一个750的设计稿来说,font-size=75px,而这个就是rem的基准值。这样一来,对于视觉稿上的元素尺寸换算,只需要原始的px值除以rem基准值即可。例如此例视觉稿中的图片,其尺寸是176px * 176px,转换成为2.346667rem * 2.346667rem。

lib-flexible 原理

1. 计算页面的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下,3和3以上的屏,用3倍的方案,2用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;
}

2. 改写页面meta标签

flexible实际上就是能过JS来动态改写meta标签,代码类似这样:

var metaEl = doc.createElement('meta');
var scale = 1 / dpr;
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
    document.documentElement.firstElementChild.appendChild(metaEl);
} else {
    var wrap = doc.createElement('div');
    wrap.appendChild(metaEl);
    documen.write(wrap.innerHTML);
}

如何转换rem

对于使用webpack的来说,其实也是有一个postcss插件的px2rem,可以很轻松的配置相关属性,转换成相对于的rem单位。比如我们的.postcssrc 配置如下:

module.exports = {
  "plugins": {
    "postcss-px2rem": {
      baseDpr: 1,
      remUnit: 37.5,
      onePxComment: '1px',
      forcePxComment: '!px',
      keepComment: '!no',
      forcePxProperty: ['font-size'] // font-size强制使用px单位
    }
  }
}

1. 文本字号不建议使用rem

前面大家都见证了如何使用rem来完成H5适配。那么文本又将如何处理适配。是不是也通过rem来做自动适配。

显然,我们在iPhone3G和iPhone4的Retina屏下面,希望看到的文本字号是相同的。也就是说,我们不希望文本在Retina屏幕下变小,另外,我们希望在大屏手机上看到更多文本,以及,现在绝大多数的字体文件都自带一些点阵尺寸,通常是16px和24px,所以我们不希望出现13px和15px这样的奇葩尺寸。

如此一来,就决定了在制作H5的页面中,rem并不适合用到段落文本上。所以在Flexible整个适配方案中,考虑文本还是使用px作为单位。只不过使用[data-dpr]属性来区分不同dpr下的文本字号大小。

配置完成之后,在实际使用时,你只要像下面这样使用:

.selector {
    width: 150px;
    height: 150px; 
    font-size: 12px; 
    border: 1px solid #ddd; 
}

px2rem处理之后将会变成:

.selector {
    width: 2rem;
   height: 2rem;
    border: 1px solid #ddd;
}
[data-dpr="1"] .selector {
    font-size: 12px;
}
[data-dpr="2"] .selector {
    font-size: 28px;
}
[data-dpr="3"] .selector {
    font-size: 42px;
}

因为不同的dpr,屏幕会缩成不同比例,所以这里的字号会根据dpr进行相应的放大。举个例子,如果data-dpr = 2 那么页面的viewport会被缩小,所以字号需要相应的乘以比例进行放大。


文章作者: feico
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 feico !
评论
  目录