Open kof opened 7 years ago
That's definitely an interesting approach, thanks for bringing it up. Ultimately it's not very different than what's done in Samsara. The difference being that it puts more of the logic into CSS, as if CSS makes the layout scaffolding of your app, and the CSS provide hooks (in the form of custom CSS properties) to JavaScrip to mutate its variables. One immediate benefit is that is provides a nice mechanism for letting the animation thread (as opposed to main thread) do the work when you don't need to interrupt the animation from the main thread when you use CSS animations.
Take the case where a <div>
is being dragged by your finger, though. Here the underlying x and y positions are animating at the same frequency as you want the CSS properties to change. Even if there's a CSS animation property on the element, It's unclear how the performance would be, or if that CSS animation property would be useful at all (would it interpolate between frames better? would this have a cost?). I'd also be curious to see how this scales to a larger application, where you'd need to expose dozens if not hundreds of custom CSS variables.
As someone who knows a lot about CSS in JS, maybe you have some opinions on how this approach could be made more modular in JS land, instead of going back and forth between CSS and JS.
I am def. not talking about pure CSS animtations, they are for sure more performant because in separate thread, but they completely lack the control part.
From the performance perspective, inline styles manipulation vs css rule manipulation should be similar by design, but
style
object, because it does a bunch of stuff.The benefits of manipulating CSS variables instead of direct properties via inline styles has more to do with authoring than with performance. I think the performance benefits (not measured) are negligible - non-trivial animations can still run smoothly at 60fps.
CSS variables are especially useful for animations specific to certain media queries (or even Safari's new reduced-animation media query), cascading/inheriting styles, pseudo-elements, and more.
Basically RxCSS is just a springboard for developers to start experimenting with using Observable streams and reactive programming for animations. You can always .subscribe
to RxCSS' output and do whatever you want with the values - even apply them to inline styles, if you'd like. Completely agnostic.
Depending on the internals it might be more work to update inline styles
But, it depends on the purpose of the library too. Samsara needs to manipulate the CSS transforms of all its elements. This means there would need to be a new stylesheet associated with each element.
So the question is, which is better:
<style>
element every animation frame).style.transform
property of the element's native style object without JSS.The use case may matter.
Both of those methods (when written with JSS), are almost the same complexity to write from an author perspective. Determining which is more performant will (correct me if wrong on the JSS usage @kof) depend on which of the following three examples performs better. In each example, make the assumption that the code is associated with (encapsulated in) a single instance of Samsara Surface
(correct me if wrong on those parts @dmvaldman):
-- 1 -- Stylesheet method with JSS stylesheet:
// This code is conceptual, and similar code would be distributed within Surface/DOMOutput/Engine classes:
this._elementStyleSheet = jss.createStyleSheet({}, {linked: true}).attach()
this._elementStyleRule = this._elementStyleSheet.createRule({
transform: 'matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)' // default initial value
})
this._currentTarget // the DOM element
.className = this._elementStyleRule.className
requestAnimationFrame(function loop() {
requestAnimationFrame(loop)
surface._elementStyleRule.prop('transform', 'matrix3d(<NEW TRANSFORM VALUES HERE>)')
})
-- 2 -- Inline method with JSS rule, no stylesheet:
// This code is conceptual, and similar code would be distributed within Surface/DOMOutput/Engine classes:
this._elementStyleRule = jss.createRule({
transform: 'matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)' // default initial value
})
this._elementStyleRule.applyTo(
this._currentTarget // the DOM element
)
requestAnimationFrame(function loop() {
requestAnimationFrame(loop)
surface._elementStyleRule.prop('transform', 'matrix3d(<NEW TRANSFORM VALUES HERE>)')
surface._elementStyleRule.applyTo(surface._currentTarget)
})
-- 3 -- The third method doesn't need an example, it is the current method implemented in Samsara, and is similar in concept to applying a JSS rule directly to the target element. Using JSS in this case might serve as a way to abstract that functionality away (handled by JSS), whereas currently it is handled by DOMOutput. The performance may be almost the same as method 2, and boils down to
requestAnimationFrame(function loop() {
requestAnimationFrame(loop)
surface._currentTarget.style.transform = 'matrix3d(<NEW TRANSFORM VALUES HERE>)'
})
In my case, I am using JSS to apply static styles to each DOM element (no animations to those properties), and I'm applying transform style by hand.
Based on this prototype https://github.com/davidkpiano/RxCSS and this presentation https://www.youtube.com/watch?v=lTCukb6Zn3g
I thought it might be interesting to see how much benefit it will provide if animating stuff by manipulating sheet rules instead of nodes directly. In this talk he is using css variables which are not supported everywhere, though it doesn't matter one can manipulate rules which apply using classes to the elements.