sticky 空白
最近在开发过程中遇到一个有意思的现象,当使用 sticky position 定位的时候,如果它的同层上面元素的高度是浮点数的话,该定位在滑动过程中将会产生一个小的空白间隙。
例如布局代码:
<div class="app">
<div class="header">
这块如果高度是浮点,将会在黏住的时候,留下间隔
</div>
<div class="content">
<div class="slider">
这块如果高度是浮点,将会在黏住的时候,留下间隔
</div>
<div class="filter"></div>
<div class="footer"></div>
</div>
</div>
css 布局代码如下:
body {
margin: 0;
padding: 0;
background: white;
overflow: auto;
}
.app {
height: 10000px;
}
.header {
position: -webkit-sticky;
position: sticky;
top: 0;
height: 50px;
background: green;
}
.slider {
height: 70.9px; /* 注意这里是一个浮点数 */
background-color: pink;
}
.slider-content {
height: 71px;
}
.content {
height: 850px;
background-color: yellow;
}
.filter {
position: -webkit-sticky;
position: sticky;
top: 50px;
height: 50px;
background-color: red;
}
.footer {
height: 40.9px; /* 这里的不会产生空白 */
background-color: #fff;
}
filter 元素采用 sticky 定位后,slider 元素的高度为浮点数,在页面往上滑动的过程中,将会产生一个1px的空白间隙。导致滑动过程中可以看见底层的元素,对用户体验不是很友好,在线演示地址:sticky 浮点数字布局
但是当布局采用 fixed 或 position 定位的时候并不会出现这样的问题,这里应该是和浏览器处理小数渲染问题有关,这里暂且认为是一个 sticky 布局的 bug(有知道具体的原因的请告诉我)。
目前如果要解决这个问题,采用的方法是等页面全部布局好之后,动态将影响 sticky 布局元素的同级上层元素高度设置为整数。不过这也让我对浏览器处理小数渲染产生兴趣,那么浏览器怎么渲染小数或者百分比呢?
保留个数
浏览器在处理小数点个数的时候,如果元素宽度为 30.33333333px。通过 getComputedStyle 得到的宽度是 30.32812px,保留了后五位小数,当然由于计算机并不能精准的表示小数,所以才会有这样的结果。通过比较后,看出 getComputedStyle 输出有效数是 6 位(macos chrome)。
具体可以通过查看 Alex Kilgour 的 带小数位的百分比、像素测试页面。
渲染规则
在一般的业务开发中,我们手写宽度,一般很少写到小数点,不过如果在业务中用到了 rem 布局方案的话,会面临到这个问题,插件会帮你自动转变 px 为 rem,就会产生小数的问题。因为根据 html 的 font-size 来确定元素宽高的话,不一定都是整数。理想的渲染当然是能渲染出真实的宽度,但是屏幕是由像素点构成的,只能渲染出单个像素点(或者亚像素渲染)。在浏览器中,对于小数的处理有各自不同的方案,归纳起来大概有 3 种,往下取整,四舍五入,智能补偿。
往下取整:浏览器会直接忽略小数点部分,真实渲染后宽度为往下取整的宽度,例如一个元素宽为 208.8px。渲染到屏幕上宽度为 208px。
四舍五入:顾名思义,就是当宽度为浮点数时,会将宽度进行取舍处理得到整数,最终渲染出来。例如:width 是 208.4px 的 208.6px 的宽度。
智能补偿:前面 2 种主要是早期浏览器的行为,现代浏览器会智能计算各个 div 的宽度。先采用四舍五入将计算结果拿到真是的值,然后将不足的或者超过的补偿给下个元素。例如 3 个宽度为 208.4px 的 div 并排在一起。
注意看第 2 个 208.4px 的元素,当你用 offsetWidth 去拿渲染后的值的时候,会得到 209px。实际上采用的计算方法是补偿计算,及前一个多出的 0.4px 会增加到后一个元素上,所以第二个得到 208.8px。四舍五入为 209px。多渲染出的 0.2px 会在下一个元素上减去。第三个计算后为 208.2px。真是渲染为 208px,以此类推。
亚像素渲染
前面提到过浏览器渲染是一个像素一个像素渲染的,就导致在处理小数的时候,实际会渲染为一个真实小数点,不会还有一种渲染技术被称为亚像素渲染。简单说,一个像素是由红绿蓝三原色组成的。而该技术能单独独立控制红绿蓝晶体管的开关。这样一个像素能被控制的精度提高了 3 倍。
该技术最长用在字体的渲染上面,如果你通过软件截图,把字体放大后发现字体周围有彩色边框,那么该文字既是采用了亚渲染技术。可以发现用了该技术,字体看上去更加清晰,察觉不到锯齿了。
而浏览器在布局元素的时候,也会采用亚渲染技术。不过该技术由于需要将屏幕控制开关精确到三原色晶体管。就会更加消耗电量。而且该技术本质上是想通过细粒度的开关,来软提高分辨率,减少锯齿感。但是目前的设备分辨率都十分的高了,开启和关闭该技术对人的感知不是很大。所以在手机等移动设备上一般默认是关闭的。
总结
不同的浏览器对于小数的处理并不十分一致,现代浏览器大多采用智能补偿法来处理小数的布局。同时我们常用的 1px 并不是指的真实的 1 像素。比如在手机上 1px 渲染出来会比较粗,并不是手机分辨率的 1 像素。可以通过缩放来呈现真实的 1 像素。
理解了小数的渲染规则,希望以后如果碰到相似的问题对你有帮助。
如需转载,请注明文章出处和来源网址:http://www.divcss5.com/html/h63560.shtml