rem 产生的小数像素问题

2015/11/05 · CSS · 1
评论
·
rem

原文出处: 淘宝前端团队(FED)-
颂晨
   

威尼斯人线上娱乐 1

由于日常需求以无线居多,所以可以在业务中做一些尝试,如
rem,刚接触这个特性的时候,曾经一度爱不释手,仿佛在无线开发的坎坷路上寻找到一条捷径。然而随着使用范围的扩大,慢慢的发现了一些使用
rem 带来的问题。

适配是什么:在不同尺寸的手机设备上,页面相对性的达到合理的展示(自适应)或者保持统一效果的等比缩放(看起来差不多)

rem

关于 rem
这个单位的介绍,在此就不赘述,有兴趣的同学可以阅读一丝的《响应式十日谈第一日:使用
rem
设置文字大小》
,文章对
rem 进行了详细的介绍。


用途

在无线开发中,响应式布局尤为重要,先不说屏幕尺寸越来越多样化的
iPhone,单是安卓就有 N 多种尺寸要适配。

在没有使用 rem 之前,想要按照设计师的想法去适配不同
分辨率1 是一件非常难操作的事情。用了 rem
以后,一切简单了许多,你可以用它来设置元素的宽高、间距…,然后针对不同的分辨率计算并设置相对应的根字体大小,然后元素就好像缩放过一样自动适应了当前的分辨率,大大的降低了适配工作量。

Demo:

威尼斯人线上娱乐 2

上图是同一个页面在 Apple iPhone 5 和 Samsung Galaxy S4
两款机器下的效果,可以看出从 320px 宽的 iPhone 5 到 360px 宽的
S4,图片像是等比放大了一样,我们分析下这个原理:

假定2 width=320px 的分辨率下的根字体大小是 32px,由此推算:

  • width=320px 分辨率下:

    根字体大小是 32px,该分辨率下宽 1rem 的元素在浏览器里的真实宽度就是
    1 * 32 = 32px;

  • width=360px 分辨率下:

    如果要达到等比放大的效果,宽 1rem 的元素在浏览器里的真实宽度就应该是
    32 * (360/320) = 36px,由此得出 width=360px 分辨率下的根字体大小为
    36px;

由此可见等比缩放是通过控制根字体大小来实现的,且根字体大小与屏幕宽度成正比。

适配元素:

1.字体

威尼斯人线上娱乐,2.宽高

3.间距

4.图像(图标、图片)  –比较复杂


小数像素

刚才举的例子里面 1rem 在 width=320px 分辨率下的真实尺寸为 32px,在
width=360px 分辨率下的真实尺寸为 36px,均为整数。

如果是 1.75rem 呢?

代表机型 浏览器宽 对应尺寸
iPhone 4/4s/5/5s 320px 56px
Samsung Note 3, Nexus 5… 360px 63px
iPhone 6 375px 65.625px
Google Nexus 6 412px 72.1px
iPhone 6 Plus 414px 72.45px

可以看到部分机型下出现了小数像素,那么浏览器是如何处理小数像素的呢?

威尼斯人线上娱乐 3

如图,第一组每个色块的大小为 1.75rem x 1.75rem,第二组每个色块的大小为
1.85rem x 1.85rem;

威尼斯人线上娱乐 4

先看第一组色块,在 iPhone 6 下,其在浏览器内的渲染尺寸应该是 1.75 *
37.5 = 65.625px;

威尼斯人线上娱乐 5

但真实渲染尺寸却是另外一种情况:有的宽度是 66px,有的却是
65px,而且顺序上毫无规律。

这一结果让我十分疑惑,如果浏览器统一做四舍五入处理,那么所有的色块尺寸也应该是一样的,不会出现部分向上取整,部分向下取整。

思考许久无果,大胆设想了一下:浏览器在渲染时所做的舍入处理只是应用在元素的渲染尺寸上,其真实占据的空间依旧是原始大小。

也就是说如果一个元素尺寸是 0.625px,那么其渲染尺寸应该是 1px,空出的
0.375px 空间由其临近的元素填充;同样道理,如果一个元素尺寸是
0.375px,其渲染尺寸就应该是 0,但是其会占据临近元素 0.375px
的空间。于是就顺着这个思路验证了以下:

  1. 第一个色块的宽度为 65.625px,根据四舍五入的原则其最终渲染尺寸为
    66px,空出的 0.375px 由第二个色块补上;
  2. 第二个色块向左补进 0.375px,相当于减少了 0.375px,余下
    65.25px,根据四舍五入的原则其最终渲染尺寸为 65px,多出的 0.25px
    会占用第三个色块的空间;
  3. 第三个色块被占用了 0.25px,相当于增加了 0.25px,等于
    65.875px,根据四舍五入的原则其最终渲染尺寸为 66px,空出的 0.125px
    由第四个色块补上;
  4. 第四个色块向左补进 0.125px,相当于减少了 0.125px,余下
    65.5px,根据四舍五入的原则其最终渲染尺寸为 66px,空出的 0.5px
    由第五个色块补上;
  5. 第五个色块向左补进 0.5px,相当于减少了 0.5px,余下
    65.125px,根据四舍五入的原则其最终渲染尺寸为 65px,多出 0.125px;

上述验证与浏览器输出结果完全一致,表明浏览器在处理小数像素的时候并不是直接舍入处理的,元素依旧占据着应有的空间,只是在计算元素尺寸的时候做了舍入处理(后来在看到LayoutUnit

WebKit
 这篇文档后,也印证了之前的假设)。

你可以参考上述原理对第二组色块进行验证,然后比对结果

适配的方法:

1.百分比适配

         百分比布局问题:

                  1.百分比的值不好计算

                  2.需要确定父级的大小,因为要根据父级的大小进行计算

                  3.宽度可以设置,但是高度不好设置

         总结:一般情况下百分比布局是需要配合其他的布局而使用


2.比例缩放适配

         把所有机型的设备独立像素设置成一致的(以前淘宝使用过这种方法)

                 
1.viewport需要通过js动态设置(不能直接把device的值设置成数值)

                  js代码:

“`

                      (function(){

                          /**

                          以iPhone6 plus为例子:

                          原来的尺寸:  curweidth 414

                          要变成的尺寸:targetwidth 375

                          比例:scale  ?

                          换算scale方法:

                          如:414/比例=375

                          那么:比例=414/375

                          所以:scale=curweidth/targetwidth

                          */

                          varcutWidth = window.screen.width;

                          vartargetWidth = 375;

                          varscale=curWidth/targetWidth;

                          varmeta = document.createElement(“meta”);

                          meta.name=’viewport’;

                         
meta.content=’initial-scale=’+scale+’,minimum-scale=’+scale+’,maximum-scale=’+scale+”;

                          document.head.appendChile(meta);

                  }()

“`

                 
2.通过设置比例(初始比例以及缩放比例),把宽度缩放成一致的

                  代码:

                 
注意:viewport里给了缩放值以后,最终的页面的宽度是原来的值除以缩放比例

                  缺点:

                 
1.就像viewport设置宽度的时候,可以吧宽度设置成一个固定值一样,会出现所有手机看上去都是同样的小没有分别了,不太好

                 
2.算出的值在一些有小数的情况下可能会出现误差(无关紧要),因为设备独立像素不能有小数


3.viewport适配

        
比例缩放适配:根据dpr的值,吧饰扣进行缩放,缩放到wuli像素,也是把屏幕的尺寸直接设置成它对应的物理像素。(淘宝在用,不过他只处理了dpr为2的几个设置,以及iPhone6
plus)

         缺点:

        
1.这种方法有时候不准确,比如dpr不为整数的时候,会出现除不尽的情况,那缩放的倍数会出现很长的小数,再去算物理像素的时候就会有误差

         2.如果屏幕的分辨率是非标准的话,算出的物理像素就是非标准的。

         /**

         同上个方法类似

         */

         js代码:

                  varscale=1/window.devicePixelRatio;

                  varmeta = document.createElement(“meta”);

                  meta.name=’viewport’;

                 
meta.content=’initial-scale=’+scale+’,minimum-scale=’+scale+’,maximum-scale=’+scale+”;

                  document.head.appendChile(meta);

         }()


4.rem适配

什么是rem适配:

         px:绝对单位,给多少就是多少

         问题:不管屏幕尺寸怎么变化,它都不会变,做不到适配

         em:相对单位,相对于自身字体大小的值

         font-size:12px  1em=12px

         问题:

                 
1.chrom下有最小字体限制,必须为12px,所以这个值不能小于12

                  2.如果两个一样的元素,但是里面字体不一样,那就不能

                  统一设置了,或者元素字体变化了,就又要统一设置一遍

         rem  CSS3新增的一个相对单位,相对于根节点(HTML)字体大小的值

                  r  root

                  html{font-size:10px}    2rem=20px

                 
通过它就可以做到只修改根元素的大小,就能成比例地调整所有的字体大小,只依赖html字体的大小