先来说说需求
某日看到某文发现其网站有一很舒适的设计,即当你向下看文章的时候会提示你看到多少了。细心一想这个主意还是蛮有用的,遂「抄袭」之。
开撸
呵,不就是这么个小小的功能么,都不用打开我的Sublime,vi都搞定了。
- 先画个
div
,然后position: fixed
到最顶部,然后width: 0
调整颜色 balabala….- 然后根据js监听浏览器滚动,用已滚动的部分的高度
-
文章距离顶部的高度=
已阅读部分文章的高度。然后用这个高度除以文章总高度就等于阅读百分比。
|
|
看起来好像咩有什么问题了,于是浏览器刷新调试… 好像和别人的效果不太一样,别人的是舒畅的音乐的感觉,我这一卡一卡的感觉像便秘…
恩,可能是因为没有动画吧。祭出我的杀器:transition: all 0.3s
动画神马必备,看了看效果好像好点了。不过感觉还是有些卡顿,心理作用?
好吧,可能是 width
触发重绘(repaint)了。
关于浏览器重绘请移步:Avoiding Unnecessary Paints
那不用 width: 100%
如何做到从 0% - 100% 的阅读进度提示呢?另外一个好的方案是 translateX
或者更好的方案 translate3d
, 为啥?因为相比 width
的变换,translate
不会引发重绘,这对于性能上有优势。而 translateX
和 translate3d
相比,前者已经足够好了但是后者会开启GPU加速,理论上性能更好。所以最后的CSS看起来是酱紫的:
|
|
CSS的性能优化到这里就要结束啦,其实 position: fixed
已经引发了重绘,优化 width
什么的都是自我安慰。但在以后的项目中还是尽量少的触发重绘,用户体验毕竟是由众多细小的细节组成的。
接下来聊聊JS,这样写功能上是没有太大问题的。问题在于 onscroll
是否性能足够优秀?
参考该文: Scrolling Performance Fixing a parallax scrolling website to run in 60 FPS Leaner, Meaner, Faster Animations with requestAnimationFrame
夜太长,字太多。不如我来总结一下,总得来说在浏览器滚动的过程中尽量避免图片大小的缩放、bow-shadow
、width
、height
等变化。在循环动画等问题上尽量避免使用 setTimeout
而是使用 requestAnimationFrame
去代替。这和本文有什么关系呢?在我们的 onscroll
中调用的 render()函数会在滚动发生的时候去触发。其实这是很没有必要的,可以通过加锁的形式让其 60fps
的速度去刷新。具体来看代码可能是酱紫的:
|
|
在移动端应该使用 touchmove
事件而不是 onscroll
事件,但即使使用了 touchmove
事件在我的 ios 8.3 chrome version 42.0上仍然有问题,因为Chrome考虑到性能问题跳过了 touchmove
事件。通常来说使用 onscroll
事件在众多移动端浏览器上事件触发是在滚动结束后才触发。而PC端是只要滚动就能触发,因此随滚动而产生的动画会比较流畅。但如果是滚动结束后才产生,那就会表现的有点卡。其实不是性能问题。而 touchmove
在移动端却可以连续触发。虽然在某些浏览器上还是有Bug。
onscroll Event Issues on Mobile Browsers Touch events in Chrome Android
那么这个问题真的没法解决吗? iScroll 的解决办法是用 JS 模拟滚动,而对于本需求来说确实有那么点杀鸡用牛刀的感觉,毕竟不是什么核心需求。所以直到目前位置这个问题依然在 ios android上 没有解决,期待以后的解决方案。
头图来自Dribbble @Jamal