1.问题背景
使用rem作尺寸单位时,假设父元素的宽度是流式并排在同一行内两个子元素宽度之和,那么当缩放浏览器窗口时,可能会出现子元素宽度之和超过父元素的宽度,从而导致第二个子元素被挤出去。原因是浏览器在将rem转成px时有轻微的偏差,但足以导致布局失败。当火狐浏览器窗口缩放到569px时,原本应该在一行的两个红框分行了。
目前的方法是将父元素display设为table,子元素display设为table-cell,(不用float)。如果一定要用float排列子元素,有没有其他解决办法呢?
2.解决方案
到目前为止,每个浏览器对小数点的处理方式都不一样。
主要有三种:处理成整数、保留4位小数或保留15位小数。现代浏览器基本支持保留小数位的处理。由于显示器是由像素单元组成的,对于小于1像素的部分,是无法像像素级那样精确地处理的,而是采用亚像素渲染的方式进行处理。
那么问题知道了,要解决此类问题,就需要对亚像素的原理有所了解,建议阅读这篇文章: Subpixel rendering 。
回到题主的主题上来。Rem转px引起的问题。就这个问题 淘宝UED的颂晨同学在2015年就做过相关的测试与假设。
大胆设想了一下:浏览器在渲染时所做的舍入处理只是应用在元素的渲染尺寸上,其真实占据的空间依旧是原始大小。
也就是说如果一个元素尺寸是 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;
上述验证与浏览器输出结果完全一致,表明浏览器在处理小数像素的时候并不是直接舍入处理的,元素依旧占据着应有的空间,只是在计算元素尺寸的时候做了舍入处理。
另外在Webkit内核中的LayoutUnit也有做过相关的阐述:LayoutUnit - WebKit。
有关于 浏览器亚像素渲染与小数位的取舍,腾讯ISUX也有同学做过相关方面的测试,详细的文章可以阅读: 浏览器亚像素渲染与小数位的取舍。
对于此类布局,目前的解决方案很多,因为现在的布局不再局限于float、display:table之类的方案了。你完全可以考虑flexbox、grid之类的优秀布局方案。至于为什么就不展开聊了。因为这不是新东西了。就算你对float钟情,那你也可以考虑其他的单位,比如vw之类的单位,这种单位是直接来匹配你的浏览器视窗的单位。