妈妈不再用担忧个人移动端了:网易和淘宝的rem方案剖析

  从博主学习前端一路过来的经历了解到,前端移动开发是大部分从PC端转战移动端的小伙伴都很是头疼的一个问题,这边博主就根据一篇本身看过的移动开发文章来剖析一下网易和淘宝的rem解决方案,但愿可以帮助到一些从PC端转战web移动开发的小伙伴,由于是第一次写博文,写得很差的地方也但愿你们多多包涵啦(*^__^*) 嘻嘻……(ps:文章有点长,若是你如今时间紧迫,那能够先收藏,等到有时间了再回头慢慢品尝喔)javascript

首先咱们一块儿看看这篇打通博主web移动开发任督二脉的武功秘籍吧(如下内容到分割线前是引用前端大牛的文章,方便你们理解博主内容):css

从网易与淘宝的font-size思考前端设计稿与工做流

1. 简单问题简单解决

我以为有些web app并必定很复杂,好比拉勾网,你看看它的页面在iphone4,iphone6,ipad下的样子就知道了:html

imageimage

image

它的页面有一个特色,就是:前端

  • 顶部与底部的bar无论分辨率怎么变,它的高度和位置都不变
  • 中间每条招聘信息无论分辨率怎么变,招聘公司的图标等信息都位于条目的左边,薪资都位于右边

这种app是一种典型的弹性布局:关键元素高宽和位置都不变,只有容器元素在作伸缩变换。对于这类app,记住一个开发原则就好:文字流式,控件弹性,图片等比缩放。以图描述:java

image

这个规则是一套基本的适配规则,对于这种简单app来讲已经足够,同时它也是后面要说的rem布局的基础。另外对于拉勾这种app可能须要额外媒介查询对布局进行调整的就是小屏幕设备。举例来讲,由于如今不少设计稿是根据iphone6的尺寸来的,而iphon6设备宽的逻辑的像素是375px,而iphone4的逻辑像素是320个像素,因此若是你根据设计稿作出来的东西,在iphone4里面可能显示不下,好比说拉钩网底部那个下载框,你对比看下就知道了,这是4:git

image

这是6:github

image

via6下面两边的间距比4多不少,说明拉勾对4确定是作过适配的,从代码也能够证明这一点:原文来自:http://caibaojian.com/mobile-responsive-example.htmlweb

image

不过若是你拿到的是根据4的设计稿,那就没有问题,比4分辨率大的设备确定能显示根据4的尺寸作出来的东西。sass

还有一点,这种状况css尺寸单位用px就好,不要用rem,避免增长复杂度。app

2. 网易的作法

先来看看网易在不一样分辨率下,呈现的效果:

image原文来自http://caibaojian.com/mobile-responsive-example.html

imageimage

从上面几张图能够看出,随着分辨率的增大,页面的效果会发生明显变化,主要体如今各个元素的宽高与间距。375*680的比320*680的导航栏明显要高。可以达到这种效果的根本缘由就是由于网易页面里除了font-size以外的其它css尺寸都使用了rem做为单位,好比你看导航栏的高度设置代码:

image

但是在本文第1部分提到,使用rem布局结合在html上根据不一样分辨率设置不一样font-size有不少很差解决的麻烦,网易是如何解决的呢?最根本的缘由在于,网易页面上html的font-size不是预先经过媒介查询在css里定义好的,而是经过JS计算出来的,因此当分辨率发生变化时,html的font-size就会变,不过这得在你调整分辨率后,刷新页面才能看获得效果。你看代码就知道为啥font-size是直接写到html的style上面的了(js设置的缘由):

image

它是根据什么计算的,这就跟设计稿有关了,拿网易来讲,它的设计稿应该是基于iphone4或者iphone5来的,因此它的设计稿竖直放时的横向分辨率为640px,为了计算方便,取一个100px的font-size为参照,那么body元素的宽度就能够设置为width: 6.4rem,因而html的font-size=deviceWidth / 6.4。这个deviceWidth就是viewport设置中的那个deviceWidth。根据这个计算规则,可得出本部分开始的四张截图中html的font-size大小以下:

deviceWidth = 320,font-size = 320 / 6.4 = 50px
deviceWidth = 375,font-size = 375 / 6.4 = 58.59375px
deviceWidth = 414,font-size = 414 / 6.4 = 64.6875px
deviceWidth = 500,font-size = 500 / 6.4 = 78.125px

事实上网易就是这么干的,你看它的代码就知道,body元素的宽是:

image

根据这个能够确定它的设计稿竖着时的横向分辨率为640。而后你再看看网易在分辨率为320*680,375*680,414*680,500*680时,html的font-size是否是与上面计算的一致:

image320*680

image375*680

image414*680

image500*680

这个deviceWidth经过document.documentElement.clientWidth就能取到了,因此当页面的dom ready后,作的第一件事情就是:

document.documentElement.style.fontSize = document.documentElement.clientWidth / 6.4 + 'px';

这个6.4怎么来的,固然是根据设计稿的横向分辨率/100得来的。下面总结下网易的这种作法:

  • (1)先拿设计稿竖着的横向分辨率除以100获得body元素的宽度:
    若是设计稿基于iphone6,横向分辨率为750,body的width为750 / 100 = 7.5rem
    若是设计稿基于iphone4/5,横向分辨率为640,body的width为640 / 100 = 6.4rem
  • (2)布局时,设计图标注的尺寸除以100获得css中的尺寸,好比下图:
  • image
  • 播放器高度为210px,写样式的时候css应该这么写:height: 2.1rem。之因此取一个100做为参照,就是为了这里计算rem的方便!
  • (3)在dom ready之后,经过如下代码设置html的font-size:
    document.documentElement.style.fontSize = document.documentElement.clientWidth / 6.4 + 'px';
  • 6.4只是举个例子,若是是750的设计稿,应该除以7.5。
  • (4)font-size可能须要额外的媒介查询,而且font-size不能使用rem,如网易的设置:
    复制代码
    @media screen and (max-width:321px){
        .m-navlist{font-size:15px}
    }
    
    @media screen and (min-width:321px) and (max-width:400px){
        .m-navlist{font-size:16px}
    }
    
    @media screen and (min-width:400px){
        .m-navlist{font-size:18px}
    }
    复制代码

最后还有2个状况要说明:

第一,若是采用网易这种作法,视口要以下设置:

<meta name="viewport" content="initial-scale=1,maximum-scale=1, minimum-scale=1">

第二,当deviceWidth大于设计稿的横向分辨率时,html的font-size始终等于横向分辨率/body元素宽:

image640*680

image641*680

之因此这么干,是由于当deviceWidth大于640时,则物理分辨率大于1280(这就看设备的devicePixelRatio这个值了),应该去访问pc网站了。事实就是这样,你从手机访问网易,看到的是触屏版的页面,若是从pad访问,看到的就是电脑版的页面。若是你也想这么干,只要把总结中第三步的代码稍微改一下就好了:

//code from http://caibaojian.com/mobile-responsive-example.html
var deviceWidth = document.documentElement.clientWidth;
if(deviceWidth > 640) deviceWidth = 640;
document.documentElement.style.fontSize = deviceWidth / 6.4 + 'px';

3. 淘宝的作法

看看淘宝在不一样分辨率下,呈现的效果:

imageimageimage

淘宝的效果跟网易的效果实际上是相似的,随着分辨率的变化,页面元素的尺寸和间距都相应变化,这是由于淘宝的尺寸也是使用了rem的缘由。在介绍它的作法以前,先来了解一点关于viewport的知识,一般咱们采用以下代码设置viewport:

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

这样整个网页在设备内显示时的页面宽度就会等于设备逻辑像素大小,也就是device-width。这个device-width的计算公式为:

设备的物理分辨率/(devicePixelRatio * scale),在scale为1的状况下,device-width = 设备的物理分辨率/devicePixelRatio 。

devicePixelRatio称为设备像素比,每款设备的devicePixelRatio都是已知,而且不变的,目前高清屏,广泛都是2,不过还有更高的,好比2.5, 3 等,我魅族note的手机的devicePixelRatio就是3。淘宝触屏版布局的前提就是viewport的scale根据devicePixelRatio动态设置:

image在devicePixelRatio为2的时候,scale为0.5

image在devicePixelRatio为3的时候,scale为0.3333

这么作目的固然是为了保证页面的大小与设计稿保持一致了,好比设计稿若是是750的横向分辨率,那么实际页面的device-width,以iphone6来讲,也等于750,这样的话设计稿上标注的尺寸只要除以某一个值就可以转换为rem了。经过js设置viewport的方法以下:

var scale = 1 / devicePixelRatio;
document.querySelector('meta[name="viewport"]').setAttribute('content','initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');

淘宝布局的第二个要点,就是html元素的font-size的计算公式,font-size = deviceWidth / 10:

image

接下来要解决的问题是,元素的尺寸该如何计算,好比说设计稿上某一个元素的宽为150px,换算成rem应该怎么算呢?这个值等于设计稿标注尺寸/该设计稿对应的html的font-size。拿淘宝来讲的,他们用的设计稿是750的,因此html的font-size就是75,若是某个元素时150px的宽,换算成rem就是150 / 75 = 2rem。总结下淘宝的这些作法:

  • (1)动态设置viewport的scale
    var scale = 1 / devicePixelRatio;
    document.querySelector('meta[name="viewport"]').setAttribute('content','initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
  • (2)动态计算html的font-size
    document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + 'px';
  • (3)布局的时候,各元素的css尺寸=设计稿标注尺寸/设计稿横向分辨率/10
  • (4)font-size可能须要额外的媒介查询,而且font-size不使用rem,这一点跟网易是同样的。

最后还有一个状况要说明,跟网易同样,淘宝也设置了一个临界点,当设备竖着时横向物理分辨率大于1080时,html的font-size就不会变化了,缘由也是同样的,分辨率已经能够去访问电脑版页面了。

image

image

关于这种作法的具体实现,淘宝已经给咱们提供了一个开源的解决方案,具体请查看:

https://github.com/amfe/lib-flexible

以前没有找到这相关的资料,实在很差意思:(

4. 比较网易与淘宝的作法

共同点:

  • 都能适配全部的手机设备,对于pad,网易与淘宝都会跳转到pc页面,再也不使用触屏版的页面
  • 都须要动态设置html的font-size
  • 布局时各元素的尺寸值都是根据设计稿标注的尺寸计算出来,因为html的font-size是动态调整的,因此可以作到不一样分辨率下页面布局呈现等比变化
  • 容器元素的font-size都不用rem,须要额外地对font-size作媒介查询
  • 都能应用于尺寸不一样的设计稿,只要按以上总结的方法去用就能够了

不一样点

  • 淘宝的设计稿是基于750的横向分辨率,网易的设计稿是基于640的横向分辨率,还要强调的是,虽然设计稿不一样,可是最终的结果是一致的,设计稿的尺寸一个公司设计人员的工做标准,每一个公司不同而已
  • 淘宝还须要动态设置viewport的scale,网易不用
  • 最重要的区别就是:网易的作法,rem值很好计算,淘宝的作法确定得用计算器才能用好了 。不过要是你使用了less和sass这样的css处理器,就好办多了,以淘宝跟less举例,咱们能够这样编写less:
复制代码
//定义一个变量和一个mixin
@baseFontSize: 75;//基于视觉稿横屏尺寸/100得出的基准font-size
.px2rem(@name, @px){
    @{name}: @px / @baseFontSize * 1rem;
}
//使用示例:
.container {
    .px2rem(height, 240);
}
//less翻译结果:
.container {
    height: 3.2rem;
}
复制代码

5. 如何与设计协做

前端与设计师的协做应该是比较简单的,最重要的是要规范设计提供给你的产物,一般对于前端来讲,咱们须要设计师提供标注尺寸后的设计稿以及各类元素的切图文件,有了这些就能够开始布局了。考虑到Retina显示屏以及这么多移动设备分辨率却不同的问题,那么设计师应该提供多套设计稿吗?从网易和淘宝的作法来看,应该是不用了,咱们能够按照设计稿,先作出一套布局,按照以上方法作适配,因为是等比适配,因此各个设备的视觉效果差别应该会很小,固然也排除不了一些须要媒介查询特殊处理的状况,这确定避免不了的。下面这张图是淘宝设计师分享的他们的工做流程:

image

解释一下就是:

第一步,视觉设计阶段,设计师按宽度750px(iphone 6)作设计稿,除图片外全部设计元素用矢量路径来作。设计定稿后在750px的设计稿上作标注,输出标注图。同时等比放大1.5倍生成宽度1125px的设计稿,在1125px的稿子里切图。

第二步,输出两个交付物给开发工程师:一个是程序用到的@3x切图资源,另外一个是宽度750px的设计标注图。

第三步,开发工程师拿到750px标注图和@3x切图资源,完成iPhone 6(375pt)的界面开发。此阶段不能用固定宽度的方式开发界面,得用自动布局(auto layout),方便后续适配到其它尺寸。

第四步,适配调试阶段,基于iPhone 6的界面效果,分别向上向下调试iPhone 6 plus(414pt)和iPhone 5S及如下(320pt)的界面效果。由此完成大中小三屏适配。

注意第三步,就要使用咱们以上介绍的网易跟淘宝的适配方法了。假如公司设计稿不是基于750的怎么办,其实很简单,按上图作一些相应替换便可,可是流程和方法仍是同样的。解释一下为何要在@3x的图里切,这是由于如今市面上也有很多像魅蓝note这种超高清屏幕,devicePixelRatio已经达到3了,这个切图保证在全部设备都清晰显示。

 

以上是博主学习移动开发参考的一遍文章,博主分割线如下的总结也是基于以上这篇文章:

原文出处:原文飞机票

——————————————————————————————————我是华丽的分割线———————————————————————————————————

 

网易rem方案:

 

前提

 

<meta name="viewport" content="initial-scale=1,maximum-scale=1, minimum-scale=1">

  

优点:

  不用管DPR,只需知设计稿宽度

 

已知:

  假设现有iPhone6设计稿,宽750px,其中一元素宽150px;

根据DPR值,iPhone6的DPR值为2,咱们可得其中该元素的显示尺寸:

真实显示CSS值:

 

 

如今咱们用网易方案来解决这个问题:

  首先咱们取1rem = 100px为参考值这个值能够随便取,为什么取这个值容后解答

  可知body的宽度:

 

  又由于body的宽度为7.5rem,由“网易公式”可得:

  Html的font-size为:

 

  Dw为deviceWidth,即设备宽度,这是整个方案里惟一动态改变的值

  现咱们已知设计稿为iPhone6,又知iPhone6的设备宽为375px,

  这时候咱们再回头看:

  html当前设备的font-size:

 

  且:

 

  可知,无形中这步已帮咱们做了DPR换算;750px的设计稿,显示在375px的屏幕要怎样转换。

  前面咱们取了1rem = 100px,可得该元素宽:150px = 1.5rem,

  又知rem为其余元素相对根元素(html)的大小

  因此可得当前元素宽度的真实css显示值为:1.5rem*50px = 75px;(这里的75px就跟咱们前面理想获得的75px不谋而合了)。

  这边咱们把这个运算再拆解来看:

 

  现再回头看:就能够知道为何当时要取100px为参考值,取这个值的意义就是为了方便运算。

 

 

总结:

  咱们只需以iPhone6的设计稿(当前主导的机型),750px宽完成一套页面,当去到其余设备时,由于咱们用的都是rem值,只须要经过JS动态得到当前的dw,再经过动态获取的dw改变html的font-size值,页面的其余元素也会由于html的改变而进行等比例缩放。

 

 

步骤:

  1.根据设计稿尺寸完成页面;

  2.设置meta,控制视口宽度,让页面以1:1比例渲染页面

  3.动态设置html的font-size;

  4.把各元素的px值除以100转换为rem(字体除外)

 

网易方案关键代码:

    设置视口: 

<meta name="viewport" content="initial-scale=1,maximum-scale=1, minimum-scale=1">

    动态设置html的font-size:

document.documentElement.style.fontSize = document.documentElement.clientWidth / 7.5 + 'px';

 

——————————————————————————————————我是华丽的分割线———————————————————————————————————

淘宝rem方案:

(1)根据设计稿尺寸完成页面切图。

(2)经过JS得到当前设备的DPR值,而后动态设置meta的scale值。scale值为缩放值,控制页面的渲染比例。

   假设当前设计稿宽为750px的Ipone6设计稿,咱们也按照这个尺寸实现了页面。若是当前打开页面的设备为Iphone6(如下简称IP6),IP6的设备宽度为375px,让375px的视口宽度也实现750px的页面确定是装不下的(显示不彻底,有滚动条)。

   因此咱们须要动态设置meta的scale值,经过scale值改变当前的视口宽度。虽然当前的设备宽度仍然为375px,可是咱们经过DPR值控制了当前的视口宽度为:

    

   这就至关于咱们把750px的页面放到了750px的设备(经过改变scale值模拟出来的视口)中打开,而后透过375px的设备(当前打开页面的设备)去观看(注意:这里是观看,不是渲染。) 页面。

(3)动态设置html的font-size:

    “淘宝公式”:

             

    假设当前打开的设备为IP6:

            

    假设当前打开的设备为IP5:

            

(4)把各元素的设计稿尺寸从px转换为rem:

            

    假设当前以IP6为设计稿实现的页面,其中一元素的宽度为150px,

    根据以上分析可得,当前:

              

    把150px转为rem得:

                

    再假设当前打开页面的设备为IP5,可得:

                

    那么150px的元素在当前页面显示的真实尺寸应该为:

                

    又得:

                

    经过比例可知当前页面在不一样设备之间实现了等比例缩放,就算再放到其它的手机也同样会根据动态算出的scale值实现等比例的缩放。

 

 

 

 

总结:

  咱们只需以iPhone6的设计稿(当前主导的机型),750px宽完成一套页面,经过JS获取当前设备的DPR值并动态设置meta的scale值。当去到其余设备时,由于咱们用的都是rem值,只须要通过JS动态得到当前的dw,再经过动态获取的dw改变html的font-size值,页面的其余元素也会由于html的改变而进行等比例缩放。

 

淘宝方案关键代码:

    动态设置viewport的scale: 

var scale = 1 / devicePixelRatio;
document.querySelector('meta[name="viewport"]').setAttribute('content','initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');

    以上实则只是在动态设置meta的scale

<meta name="viewport" content="initial-scale=scale,maximum-scale=scale, minimum-scale=scale">

    动态设置html的font-size:

document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + 'px';

——————————————————————————————————我是华丽的分割线———————————————————————————————————

对比网易与淘宝的解决方案:

 

共同点:

      1.都是先根据设计稿,按设计稿原始尺寸完成整套页面,而后采用rem转换实现一稿解决全部适应。

    2.都须要动态设置html的font-size属性,但公式不一样。

    3.布局时各元素的尺寸值都是根据设计稿标注的尺寸计算出来,因为html的font-size是动态调整的,因此可以在不一样的设备等比变化。

    4.容器元素的font-size都不用rem,须要额外作font-size的媒体查询。

 

不一样点:

    1.网易经过设置meta,控制视口宽度为设备宽度,让页面以1:1比例渲染;

     淘宝经过动态设置meta的scale,把视口宽度控制为设备的真实设计稿宽度。

    2.运算公式不一样:

            html的font-size运算:

                    网易:

 

                    淘宝:

 

               rem的转换:

                  网易:把各元素按设计稿的px值除去100转换为rem;

                  淘宝:各元素rem=设计稿对应px值/html的font-size;

 

     3.解决思路不一样:

            网易:把750px的页面等比例转换,压缩在375px的设备显示;

            淘宝:把750px的页面放到虚拟的750px视口渲染打开,再透过375px的设备查看页面。

 

备注:本案例分析统一以Iphone6为设计原稿。

 

  以上就是博主对于移动开发rem使用的一些我的浅见啦,但愿能对你们有所帮助吧,说得很差的地方也劳烦各位大神不吝赐教o(╯□╰)o。

 

若是你不知道什么是rem:请点击飞机票;

若是你对于移动web彻底没概念: 请点击飞机票1  请点击飞机票2

相关文章
相关标签/搜索