用rem适配移动端

常见方式:

1. 固定宽度(320)作法:这样前端却是爽了,但是大页面两边有留白,小页面图标文字又会缩的很小,用户体验极其很差。css

2. 流式布局:其实就是用%,这样宽度倒还差很少,高度怎么搞?因此这种布局通常都是宽度自适应高度写死,显的很不协调,另外对设计也有很大的限制,另外还有兼容性方面的问题。html

3. 响应式布局:说白了就是利用CSS3中的Media Query(媒介查询),喊的很火,谁用谁知道,简直累死人不要命。前端

4. 设置viewport进行缩放:以320宽度为基准,进行缩放,最大缩放为320*1.3 = 416,基本缩放到416都就能够兼容iphone6 plus的屏幕了。<meta name="viewport" content="width=320,maximum-scale=1.3,user-scalable=no">git

5. 利用vh、vw适配:兼容性太差。github

rem是什么

rem是一个相对根元素html字体大小的单位,因此它的大小是由html的fontSize大小决定的,假如我把html的fontSize设置为10px,此时的1rem就等于10px,假如我把html的fontSize设置为100px,此时的1rem就等于100px,这也正是咱们能用rem作移动端适配的根本缘由,就是经过不一样屏幕下改变根元素fontSize的大小,从而让以rem为单位的各类元素自动随着改变。web

适配标准

经过下面这句话得到理想视口(ideal viewport):chrome

<meta name="viewport" content="width=device-width">

既然要适配,就要选一个理想视口作基准,而后才能在此基础上等比缩放(这里等比缩放最好不包括文字,后面讲缘由),咱们通常选择iphone6的375,为何选它呢?浏览器

由于市场上的Android机五花八门(理想视口宽通常在320-480之间),且没有任何一款的占有率能和iphone相比,选取iphone中的iphone6能更好的向下适配iphone5和向上适配iphone6 plus等,关于各机型的理想视口(ideal viewport)详见VIEWPORT SIZESsass

设计图

上面说了咱们要以iphone6为基准,那么设计图咱们作成多大呢?dom

设计图作成750px宽,由于iphone6的物理像素是750(上面咱们说的375是它的设备独立像素,又是理想视口),咱们要想作到高清就要1个设计像素对应一个物理像素才成,他们之间的关系见下表:

  iPhone6 plus iPhone6 iPhone5
物理像素(physical pixel) 看公式 看公式 看公式
设备独立像素(density-independent pixel) 414x736 375×667 320x568
设备像素比(device pixel ratio ) 3 2 2

设备像素比(dpr),咱们能够经过JavaScript获取的办法是:window.devicePixelRatio;用CSS获取的办法是-webkit-device-pixel-ratio。咱们能够用-webkit-min-device-pixel-ratio-webkit-max-device-pixel-ratio进行媒体查询,以达到适配不一样dpr的需求。

用CSS适配

原理:用媒体查询理想视口(上面咱们把width=device-width了,因此查询width便可),不一样理想视口设置不一样的根元素fontSize。

一张750的设计稿,假如其根元素为100px(为何是100px而不是其余的呢?),此时我想表示一个750px*100px的div,我只须要写成:

div{width:7.5rem; height:1rem;}

那么问题来了,我在iphone6下把根元素字体设为多大才能让这个div等比显示呢?要想等比显示那么他们之间有这样一个关系:

100px / 750 = iphone6 根元素fontSize / iphone6理想视宽(375)

根据上面公式算出iphone6 根元素fontSize = 50px,也就是在iphone6下咱们只须要改变根元素fontSize为50px就能够作到等比缩放啦~~

那么问题又来了,手机那么多,各类机型的理想宽度也数不胜数(其实大多都在320到480之间,上面有说),那么其对应根元素fontSize我该怎么写呢?

做为一个CSSer,咱们最早想到的是媒体断点查询,例如像下面这样:

@media screen and (min-width:321px) and (max-width:375px){
  html{font-size:42px}
}
@media screen and (min-width:376px) and (max-width:414px){
  html{font-size:50px}
}
@media screen and (min-width:415px) and (max-width:639px){
  html{font-size:55px}
}
@media screen and (min-width:640px) and (max-width:719px){
  html{font-size:85px}
}
@media screen and (min-width:720px) and (max-width:749px){
  html{font-size:95x}
}
@media screen and (min-width:750px) and (max-width:800px){
  html{font-size:100px}
}

上面的缺点一目了然,就是不够精细嘛,例如415-639理想视宽的手机显示的东西倒是同样大,对于像素级要求的咱们这怎么能成呢?

因而乎我用sass把从320到750所有算一遍不就能够啦,就像下面这样:

@media (max-width: 320px){
  html{ font-size: 266.66667%; }
}
@for $i from 320 through 750 {@media (width:#{$i}px){
  html{font-size: $i/1.2 * 1%}}
}
@media (min-width: 750px){
  html{ font-size: 625%; }
}

Sass生成结果(景象过于壮观慎入),大功告成,这样咱们不用JavaScript也能实现和其同样的精细效果了。使用时只需在头部引用这样一个CSS文件便可,假如750上你量出的div大小为width:85px;height:100px;,写的时候只需除以100便可,即width:.85rem;height:1rem;你要嫌除的麻烦sublime中能够装这么一个转换插件

这时确定会有人吐槽性能问题洛,压缩后的media100px.css大概10几kb的样子,我看了下我们移动网站的一个普通商品图大概是它的2倍,固然拿两个东西进行比较是有点不太稳当,具体增长这么些样式会影响多大性能暂未验证。

之因此在750下把根元素设为100而不是其余,是由于方便计算嘛,1rem等于100px,.2rem就等与20px这样多好算啊,有人会问你丫设为10不同好算啊,话说通常浏览器显示的最小字号是12px,因此就100啦,固然数学好的你用其余值也是能够的。

上面用Sass生成的css根元素字体大小我是用%号表示的,就是100px,我写的是625%,有人可能会问你这干吗画蛇添足呢,625%不就是100px嘛,有人给出了下面几个理由,我抄下来共你们参考:

  • 某些设备的默认字体大必定是16px,特别是高分辨率的设备,设置成百分比能够按照设备的基准字体大小给编写的网页设置好最适合用户浏览的字体大小。
  • 这样写是兼容将来趋势的综合考虑,px这个单位的含义已经愈来愈混乱,几乎没法评估之后的设备是会像如今这样对网页上的px作兼容处理,但用百分比表明默认字体尺寸基本不会混乱。

用JavaScript适配

上面直接引用直接media100px.css的确不是最好的方案,你知道我要说什么啦,那就是用JavaScript适配,其实咱们把上面的Sass循环改为用JS写就行了,就像下面这样:

!(function(doc, win) {
  var docEle = doc.documentElement,
  evt = "onorientationchange" in window ? "orientationchange" : "resize",//区分Mobile和PC以加载不一样的事件
  fn = function() {
    var width = docEle.clientWidth;
    if( width < 320 ) {
      docEle.style.fontSize = 42.6667 + "px";
    }
    else if( width > 750 ) {
      docEle.style.fontSize = 100 + "px";
    }
    else {
      //以750设计稿宽度为基准设置fontSize:100px;这样保证iPhone6如下是高清
      docEle.style.fontSize = 100 * (width / 750) + "px";
    }
  };
  win.addEventListener(evt, fn, false);
  //load事件是在页面全部元素都加载完后触发;
  //DOMContentLoaded,它是指dom tree加载完就触发,页面引用的样式表和图像文件可能尚未加载完成
  doc.addEventListener("DOMContentLoaded", fn, false);
}(document, window));

在使用的时候你能够单独引用这样一段JS (看上面我又不用%而用px啦,测试(chrome模拟手机测试的)后发现%和px最终造成网页效果并没有差异),不使用不引用便可;或者把这段JS放在公共JS文件里,而对于不想使用rem的同窗只需覆盖JS设置的样式便可,例如像下面这样:

html{font-size:20px!important;}//这里移动端默认字体大小根据状况本身设置

注意事项

1.文字最好不要用rem表示,由于:

其一:设计师通常但愿是文字在移动设备上的显示大小是同样的,也就是咱们所说的等比适配(注意是等比适配不包括,不是适配)是不该包括文字的;

其二:咱们用rem后文字会很小(虽然这正是等比缩放的结果),固然这也和设计有关(理论上字体须要等比适配的话750px设计图上是不该该有小于24px字体出现的,既然有也说明字体不该该等比适配),例如我在设计图上量取的文字大小是24px,那么其iphone6下的显示大小就是.24rem*50=12px,而设计图上哪些24如下的字体此时也会显示12px(假如最小字体是12的话),这也会有另一个问题,就是设计图上明明是不一样字体大小表示的文案,在手机上显示的大小倒是同样的,起不到设计师想要表达的区分或者强调的做用;

其三:网上有说会变模糊之类的,我暂时未发现(暴漏了我依然表示字体用rem表示的...)。

解决办法:能够分断点区间,设置不一样的fontSize大小,能够参考点我

2.1px和2px不要写成.01rem和.02rem,由于:

以750适配的方案为例,当理想视口为320时,其对应font-size: 266.66667%; 而后乘以默认字体大小16px,最后为42.6666672px,也就是43px,若写为.01rem或.02rem表示分别对应.42px或.96px,在直接取整的浏览器下是显示不出来的。因此对于1像素边框的就不要写.01rem啦。

3.当咱们写1px时,实际在dpr为2的手机下显示的是2个物理像素,看起来会粗一点,解决方案能够参照淘宝的flexible,其原理是根据dpr的不一样动态设置initial-scale的值,也能够用下面方法实现:

.scale {   position: relative;   height: 50px;   line-height: 50px;   background-color: #ccc;
} .scale:after {   position: absolute;   content: '';   width: 100%;   left: 0;   bottom: 0;   height: 1px;   background-color: red;   -webkit-transform: scale(1,.5);   transform: scale(1,.5);   -webkit-transform-origin: center bottom;   transform-origin: center bottom;
}

注:JavaScript适配方案是一种思路或者中心思想,在实际使用中会有其余一些问题须要注意,例如JS的加载时机以及其余有一些安卓机的奇怪问题,具体能够参考淘宝的flexible解决方法,或者参考咱们目前在用的方案:flexible精简版下载

相关文章参考:

白色橡树的整理

移动前端开发之viewport的深刻理解

移动端高清、多屏适配方案

 

以上文字友好阅读方式:点我下载