且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

清洁的方式来编程使用JS的CSS转换?

更新时间:2023-09-25 15:27:16

目前还没有一个干净的方式 James Dinsdale附近的答案有关使用CSS动画的示例)。有一个规范错误14617 ,自2011年以来没有受到太多的关注。 / p>

setTimeout 在Firefox中无法可靠运作()。



我不确定 requestAnimationFrame - 对原始问题的编辑说,它不能可靠工作,但我没有调查。 (更新:看起来像 requestAnimationFrame 至少被认为是由一个Firefox核心开发人员作为您可以进行更多更改的地方,不一定看到以前更改的效果。)



强制回流通过访问 offsetHeight )是一个可能的解决方案,但对于转换工作,应该强制restyle(即 getComputedStyle https:// timtaubert。 de / blog / 2012/09 / css-transitions-for-dynamic-created-dom-elements /

  window.getComputedStyle(elem).opacity;注意,只是运行 getComputedStyle(elem) 


$ b

有关reflow / restyle / repaint的更多信息: http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/


As the title implies, is there a proper way to set some initial CSS properties (or class) and tell the browser to transition these to another value?

For example (fiddle):

var el = document.querySelector('div'),
    st = el.style;
st.opacity = 0;
st.transition = 'opacity 2s';
st.opacity = 1;

This will not animate the opacity of the element in Chrome 29/Firefox 23. This is because (source):

[...] you’ll find that if you apply both sets of properties, one immediately after the other, then the browser tries to optimize the property changes, ignoring your initial properties and preventing a transition. Behind the scenes, browsers batch up property changes before painting which, while usually speeding up rendering, can sometimes have adverse affects.

The solution is to force a redraw between applying the two sets of properties. A simple method of doing this is just by accessing a DOM element’s offsetHeight property [...]

In fact, the hack does work in the current Chrome/Firefox versions. Updated code (fiddle - click Run after opening the fiddle to run animation again):

var el = document.querySelector('div'),
    st = el.style;
st.opacity = 0;
el.offsetHeight; //force a redraw
st.transition = 'opacity 2s';
st.opacity = 1;

However, this is rather hackish and is reported to not work on some android devices.

Another answer suggests using setTimeout so the browser has time to perform a redraw, but it also fails in that we don't know how long it will take for a redraw to take place. Guessing a decent number of milliseconds (30-100?) to ensure that a redraw occurred means sacrificing performance, unnecessarily idling in the hopes that the browser performs some magic in that little while.

Through testing, I've found yet another solution which has been working great on latest Chrome, using requestAnimationFrame (fiddle):

var el = document.querySelector('div'),
    st = el.style;
st.opacity = 0;
requestAnimationFrame(function() {
    st.transition = 'opacity 2s';
    st.opacity = 1;
});

I assume that requestAnimationFrame waits until right before the beginning of the next repaint before executing the callback, hence the browser does not batch up the property changes. Not entirely sure here, but works nicely on Chrome 29.

Update: after further testing, the requestAnimationFrame method does not work very well on Firefox 23 - it seems to fail most of the time. (fiddle)

Is there a proper or recommended (cross-browser) way of achieving this?

There isn't a clean way at this moment (without using CSS Animations -- see the nearby answer by James Dinsdale for an example using CSS Animations). There is a spec bug 14617, which didn't receive much traction since 2011.

setTimeout does not work reliably in Firefox (this is by design).

I'm not sure about requestAnimationFrame -- an edit to the original question says it doesn't work reliably either, but I did not investigate. (Update: it looks like requestAnimationFrame is considered at least by one Firefox core developer to be the place where you can make more changes, not necessarily see the effect of the previous changes.)

Forcing reflow (e.g. by accessing offsetHeight) is a possible solution, but for transitions to work it should be enough to force restyle (i.e. getComputedStyle): https://timtaubert.de/blog/2012/09/css-transitions-for-dynamically-created-dom-elements/

window.getComputedStyle(elem).opacity;

Note that just running getComputedStyle(elem) is not enough, since it's computed lazily. I believe it doesn't matter which property you ask from the getComputedStyle, the restyle will still happen. Note that asking for geometry-related properties still might cause a more expensive reflow.

More information on reflow/restyle/repaint: http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/