奇怪的渲染
为什么从其他转前端会觉得前端很难?也许是因为各种奇怪的 CSS Hacks 吧。
0. 动效残影与图层
给一个 <td>
的 :hover
伪类随便写点 transition
过渡就可能遇到这样的情况:
但是,如果同时加了一点 3D 效果,比如 translateZ(0)
,问题就又消失了。
如果看一遍 DevTools 的性能面板,就能知道区别在哪:
没有 3D 效果时,重绘 (repaint) 的图层 (layer) 是整个文档;而有 3D 效果时,这个节点会被独立成一个图层进行渲染。
打开 DevTools - More tools - Layers 或是在 Rendering 工具里勾选 Layer Borders 即可验证。
当然,translateZ(0)
会有一些副作用,所以一般会用 backface-visibility: hidden
这个本来用来控制 3D 元素背部可见性的属性来达到同样的效果。
1. 消失的底边
但是这带来了一个问题,底边没了:
如果给底边单独设双倍的高度,则可以正常显示。那么问题很明显,就是边框高度溢出了图层。
但是,这问题没有一致性,几乎一致的几个表格,不一定哪个会出现。
不过,打开 Layer Borders 可以发现一个规律:
回想之前的动效残留,可以发现这其实是同一问题。那么最简单的解决方案就是:
增大图层范围。这里增加一个 box-shadow
来撑开图层。
这时,如果把之前加的 backface-visibility: hidden
去掉,会发现它已经不再被需要了。
2. 「要开始变形了」
但是「众所周知」的是,box-shadow
会吃渲染性能的(尤其是没有优化的低版本浏览器)。
而如果去掉强制独立图层的话,整页渲染加上 box-shadow
无疑会降低性能。
这时候就要 will-change
属性,预先告诉浏览器,该元素将会对哪个属性添加动效。
浏览器支持方面,Chrome 和 Firefox 版本均为 36+。
3. 避免重绘
即便预告了 box-shadow
,但优化还是很有限,因为毕竟还有重绘的过程。
那么 box-shadow
可以不重绘吗?
给 ::after
伪元素画上盒阴影,然后用 opacity
隐藏掉,待需要时再显示。
opacity
改变的元素,会被单独放在一个图层,而且透明度改变的性能成本较低。
不过,这样就没法用来解决第一个问题了。
所以结论就是,<table>
已经没人要用了 ≡(▔﹏▔)≡
本文参考了:
[1] https://stackoverflow.com/questions/28511539/the-underlying-magic-of-webkit-backface-visibility
[2] https://www.barretlee.com/blog/2015/10/14/a-incredible-bug-in-taobao-homepage/
[3] https://www.zhangxinxu.com/wordpress/2015/11/css3-will-change-improve-paint/
[4] https://juejin.cn/post/6844903584077889544
[5] https://segmentfault.com/a/1190000011337088