rem 产生的小数像素问题
2016-07-06 15:26
316 查看
由于日常需求以无线居多,所以可以在业务中做一些尝试,如 rem,刚接触这个特性的时候,曾经一度爱不释手,仿佛在无线开发的坎坷路上寻找到一条捷径。然而随着使用范围的扩大,慢慢的发现了一些使用 rem 带来的问题。
在没有使用 rem 之前,想要按照设计师的想法去适配不同 分辨率1 是一件非常难操作的事情。用了 rem 以后,一切简单了许多,你可以用它来设置元素的宽高、间距…,然后针对不同的分辨率计算并设置相对应的根字体大小,然后元素就好像缩放过一样自动适应了当前的分辨率,大大的降低了适配工作量。
Demo:
![](http://ww1.sinaimg.cn/mw690/0064cTs2gw1exq6o5wvq4j30p00p0afe.jpg)
上图是同一个页面在 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.75rem 呢?
可以看到部分机型下出现了小数像素,那么浏览器是如何处理小数像素的呢?
![](http://ww4.sinaimg.cn/mw690/0064cTs2gw1exq6o6sxqlj30bj0l2q3m.jpg)
如图,第一组每个色块的大小为 1.75rem x 1.75rem,第二组每个色块的大小为 1.85rem x 1.85rem;
![](http://ww4.sinaimg.cn/mw690/0064cTs2gw1exq6o74jh9j308o06w3yt.jpg)
先看第一组色块,在 iPhone 6 下,其在浏览器内的渲染尺寸应该是 1.75 * 37.5 = 65.625px;
![](http://ww3.sinaimg.cn/mw690/0064cTs2gw1exq6o7joz5j30mo08cdg7.jpg)
但真实渲染尺寸却是另外一种情况:有的宽度是 66px,有的却是 65px,而且顺序上毫无规律。
这一结果让我十分疑惑,如果浏览器统一做四舍五入处理,那么所有的色块尺寸也应该是一样的,不会出现部分向上取整,部分向下取整。
思考许久无果,大胆设想了一下:浏览器在渲染时所做的舍入处理只是应用在元素的渲染尺寸上,其真实占据的空间依旧是原始大小。
也就是说如果一个元素尺寸是 0.625px,那么其渲染尺寸应该是 1px,空出的 0.375px 空间由其临近的元素填充;同样道理,如果一个元素尺寸是 0.375px,其渲染尺寸就应该是 0,但是其会占据临近元素 0.375px 的空间。于是就顺着这个思路验证了以下:
第一个色块的宽度为 65.625px,根据四舍五入的原则其最终渲染尺寸为 66px,空出的 0.375px 由第二个色块补上;
第二个色块向左补进 0.375px,相当于减少了 0.375px,余下 65.25px,根据四舍五入的原则其最终渲染尺寸为 65px,多出的 0.25px 会占用第三个色块的空间;
第三个色块被占用了 0.25px,相当于增加了 0.25px,等于 65.875px,根据四舍五入的原则其最终渲染尺寸为 66px,空出的 0.125px 由第四个色块补上;
第四个色块向左补进 0.125px,相当于减少了 0.125px,余下 65.5px,根据四舍五入的原则其最终渲染尺寸为 66px,空出的 0.5px 由第五个色块补上;
第五个色块向左补进 0.5px,相当于减少了 0.5px,余下 65.125px,根据四舍五入的原则其最终渲染尺寸为 65px,多出 0.125px;
上述验证与浏览器输出结果完全一致,表明浏览器在处理小数像素的时候并不是直接舍入处理的,元素依旧占据着应有的空间,只是在计算元素尺寸的时候做了舍入处理(后来在看到LayoutUnit – WebKit 这篇文档后,也印证了之前的假设)。
你可以参考上述原理对第二组色块进行验证,然后比对结果。
![](http://ww1.sinaimg.cn/mw690/0064cTs2gw1exq6o89wxqj31100p043z.jpg)
上图是同一组 icon 在不同机型下的效果,可以看出这些 icon 在 iPhone 5 和 Galaxy S4 下或多或少的会被裁掉一部分,原因就是由于小数像素导致的,这点可以从元素的Computed Style 上看出。
使用 iconfont;
如需使用 background-image,尽量为背景图设置一定的空白间隙,如图:
![](http://ww4.sinaimg.cn/mw690/0064cTs2gw1exq6o8sxkwj30pk0ncwid.jpg)
为了保证大部分分辨率下计算出的根字体大小都为整数,所以约定根字体大小的计算公式为:分辨率宽度 / 10;
rem
关于 rem 这个单位的介绍,在此就不赘述,有兴趣的同学可以阅读一丝的《响应式十日谈第一日:使用 rem 设置文字大小》,文章对 rem 进行了详细的介绍。用途
在无线开发中,响应式布局尤为重要,先不说屏幕尺寸越来越多样化的 iPhone,单是安卓就有 N 多种尺寸要适配。在没有使用 rem 之前,想要按照设计师的想法去适配不同 分辨率1 是一件非常难操作的事情。用了 rem 以后,一切简单了许多,你可以用它来设置元素的宽高、间距…,然后针对不同的分辨率计算并设置相对应的根字体大小,然后元素就好像缩放过一样自动适应了当前的分辨率,大大的降低了适配工作量。
Demo:
![](http://ww1.sinaimg.cn/mw690/0064cTs2gw1exq6o5wvq4j30p00p0afe.jpg)
上图是同一个页面在 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;
由此可见等比缩放是通过控制根字体大小来实现的,且根字体大小与屏幕宽度成正比。
小数像素
刚才举的例子里面 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 |
![](http://ww4.sinaimg.cn/mw690/0064cTs2gw1exq6o6sxqlj30bj0l2q3m.jpg)
如图,第一组每个色块的大小为 1.75rem x 1.75rem,第二组每个色块的大小为 1.85rem x 1.85rem;
![](http://ww4.sinaimg.cn/mw690/0064cTs2gw1exq6o74jh9j308o06w3yt.jpg)
先看第一组色块,在 iPhone 6 下,其在浏览器内的渲染尺寸应该是 1.75 * 37.5 = 65.625px;
![](http://ww3.sinaimg.cn/mw690/0064cTs2gw1exq6o7joz5j30mo08cdg7.jpg)
但真实渲染尺寸却是另外一种情况:有的宽度是 66px,有的却是 65px,而且顺序上毫无规律。
这一结果让我十分疑惑,如果浏览器统一做四舍五入处理,那么所有的色块尺寸也应该是一样的,不会出现部分向上取整,部分向下取整。
思考许久无果,大胆设想了一下:浏览器在渲染时所做的舍入处理只是应用在元素的渲染尺寸上,其真实占据的空间依旧是原始大小。
也就是说如果一个元素尺寸是 0.625px,那么其渲染尺寸应该是 1px,空出的 0.375px 空间由其临近的元素填充;同样道理,如果一个元素尺寸是 0.375px,其渲染尺寸就应该是 0,但是其会占据临近元素 0.375px 的空间。于是就顺着这个思路验证了以下:
第一个色块的宽度为 65.625px,根据四舍五入的原则其最终渲染尺寸为 66px,空出的 0.375px 由第二个色块补上;
第二个色块向左补进 0.375px,相当于减少了 0.375px,余下 65.25px,根据四舍五入的原则其最终渲染尺寸为 65px,多出的 0.25px 会占用第三个色块的空间;
第三个色块被占用了 0.25px,相当于增加了 0.25px,等于 65.875px,根据四舍五入的原则其最终渲染尺寸为 66px,空出的 0.125px 由第四个色块补上;
第四个色块向左补进 0.125px,相当于减少了 0.125px,余下 65.5px,根据四舍五入的原则其最终渲染尺寸为 66px,空出的 0.5px 由第五个色块补上;
第五个色块向左补进 0.5px,相当于减少了 0.5px,余下 65.125px,根据四舍五入的原则其最终渲染尺寸为 65px,多出 0.125px;
上述验证与浏览器输出结果完全一致,表明浏览器在处理小数像素的时候并不是直接舍入处理的,元素依旧占据着应有的空间,只是在计算元素尺寸的时候做了舍入处理(后来在看到LayoutUnit – WebKit 这篇文档后,也印证了之前的假设)。
你可以参考上述原理对第二组色块进行验证,然后比对结果。
问题
目前遇到最多的问题就是 background-image 的问题,经常会因为小数像素导致背景图被裁掉一部分。![](http://ww1.sinaimg.cn/mw690/0064cTs2gw1exq6o89wxqj31100p043z.jpg)
上图是同一组 icon 在不同机型下的效果,可以看出这些 icon 在 iPhone 5 和 Galaxy S4 下或多或少的会被裁掉一部分,原因就是由于小数像素导致的,这点可以从元素的Computed Style 上看出。
解决
如何避免这种问题呢?以下两点建议:使用 iconfont;
如需使用 background-image,尽量为背景图设置一定的空白间隙,如图:
![](http://ww4.sinaimg.cn/mw690/0064cTs2gw1exq6o8sxkwj30pk0ncwid.jpg)
小结
小数像素产生的问题不单单只有 background-image,还会有其他尚未遇到的坑,然而在了解了浏览器是如何处理小数像素的原理以后,此类问题就变得很好解决,也非常可控。注:
文中出现的分辨率都是指浏览器分辨率,关于逻辑分辨率、物理分辨率之间的关系可以参考:「像素」「渲染像素」以及「物理像素」是什么东西?它们有什么联系?;为了保证大部分分辨率下计算出的根字体大小都为整数,所以约定根字体大小的计算公式为:分辨率宽度 / 10;
相关文章推荐
- 校外分散实习(1)
- Cookie Session
- Peeking Iterator
- Qt学习之路(27): 渐变填充
- Unity3D UGUI按钮长按事件
- 第一节:安装Python
- js 程序执行与顺序实现详解
- android透明状态栏
- rtmp协议详解
- ListView里面Item元素 文字乱串问题
- iOS小技巧-使用UUID+keychain替代udid方案
- JAVA字符串格式化-String.format()的使用
- 跟我学系列之JVM远程性能监控
- 跟我学系列之RabbitMQ深入研究
- 同步,异步,阻塞和非阻塞的区别
- 跟我学系列之趣解NIO和IO的区别
- 跟我学Dubbo系列之Java SPI机制简介
- 跟我学分布式事务之2PC和3PC
- 跟学我Kakfa源码搭建环境(一)
- 跟我学Kafka源码配置文件简介(二)