Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于如何触发浏览器重绘的一些尝试。 #12

Open
sl1673495 opened this issue Nov 23, 2018 · 2 comments
Open

关于如何触发浏览器重绘的一些尝试。 #12

sl1673495 opened this issue Nov 23, 2018 · 2 comments

Comments

@sl1673495
Copy link
Owner

sl1673495 commented Nov 23, 2018

我们动态的往body节点上挂一个小球 并且更改它的top值 让它触发动画
(以下代码均在chrome控制台执行)

var div = document.createElement('div')
div.style.cssText = 'position: fixed;width: 30px; height: 30px; left: 0; top: 0; background: red;transition: all 1s'
document.body.appendChild(div)
div.style.top = '500px'

这样写是没用的,因为浏览器很聪明,它会把你在一次task中的样式更改收集起来,再执行渲染的时候再把它一次性改变,但是网上很多人说getComputedStyle这个api可以直接触发重绘,那么我们来试试

var div = document.createElement('div')
div.style.cssText = 'position: fixed;width: 30px; height: 30px; left: 0; top: 0; background: red;transition: all 1s'
document.body.appendChild(div)

// 想触发重绘
getComputedStyle(div)
div.style.top = '500px'

按理说应该会执行动画吧, 可是并没有,这很让人疑惑,我们再这样试试

var div = document.createElement('div')
div.style.cssText = 'position: fixed;width: 30px; height: 30px; left: 0; top: 0; background: red;transition: all 1s'
document.body.appendChild(div)

// 想触发重绘
getComputedStyle(div).top
div.style.top = '500px'

咦,这次终于执行动画了,看来浏览器优化程度到了这一步,就算你去getComputedStyle 它也会惰性的给你返回一个对象, 等到你真正的去读取里面的样式值,才会触发重绘。

再来一个小实验,我们想要让浏览器闪烁两个颜色

document.body.style.background = 'blue'
document.body.style.background = 'red'

显而易见这样是没用的, 那么我们用setTimeout去让中间经历一次浏览器渲染

document.body.style.background = 'blue'
setTimeout(() => { document.body.style.background = 'red' })

这次好像可以了 把这段代码在浏览器里执行多次, 会发现有时候还是会直接变成红色背景,这是为什么呢? 我们继续做个试验

document.body.style.background = 'blue'
setTimeout(() => { document.body.style.background = 'red' }, 16.7)

这段代码再执行n次, 这下每次都会闪烁两种颜色了, 16.7是个什么数字呢,我们一般电脑的屏幕刷新率是60hz,也就是每秒更新60次视图,1000ms / 60 ≈ 16.7 浏览器会根据你的屏幕刷新率去约束渲染线程的执行,去除掉多余无效的渲染。

那牵扯到硬件,假如我们的刷新率只有30hz呢, 或者更多,更少呢?
这也就是为什么浏览器给我们提供了一个api叫requestAnimationFrame,不懂的朋友们可以去查阅一下这个api的用法。
真正保证屏幕一定会闪烁两次的做法

requestAnimationFrame(() => {
  document.body.style.background = 'red' 
  requestAnimationFrame(() => {
    document.body.style.background = 'blue'
  })
})
@sl1673495 sl1673495 changed the title 关于浏览器重绘的一些尝试。 关于如何触发浏览器重绘的一些尝试。 Nov 23, 2018
@sl1673495
Copy link
Owner Author

膜拜大佬...666技术好文。这里本菜鸡也来分享一波:
之前遇到requestAnimFrame 这个api会存在兼容性的问题,
一般涉及动画可以这样,做个回调,在浏览器不支持这个api接口的时候,可以这样:
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 16.7);
};
})();

另外,有个建议,动画模块在不考虑兼容的情况,千万不要因为想要贪图方便用jq的animate(),在某些特效上会卡帧(相信有朋友也像我一样被坑过),请优先考虑使用css3。这也是一个坑。
如果,如果,要做一些比较兼容的特效,可以去了解一下animate.css,很好用。

谢谢分享

@Han3Jim
Copy link

Han3Jim commented Jun 4, 2020

不错

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants