solidjs-community / solid-transition-group

SolidJS components for applying animations when children elements enter or leave the DOM.
https://solid-transition-group.netlify.app
MIT License
254 stars 14 forks source link

Element flashes before animation starts running. #3

Closed minht11 closed 3 years ago

minht11 commented 3 years ago

Before animation runs, content appears unstyled for a brief moment.

const onEnter = (element: Element, done: () => void) => {
   // At this point element shouldn't be visible but it is.
   element.animate({
      opacity: [0, 1],
    }, {
      duration: 100,
    }).finished.then(done)
}

Reproducible example some other person made: https://codesandbox.io/s/cool-bogdan-j8b37?file=/package.json

One possible fix is to use 'onBeforeEnter' event but that only complicates things, especially with complex animations. An actual fix would be to replace all 'setTimeout' uses with 'queueMicrotask', for example here: https://github.com/ryansolid/solid-transition-group/blob/0f1d5253531246e51ea549adf8a002c7020ec5ad/src/Transition.ts#L63-L71 I have briefly tested it working locally with both native function and polyfill https://github.com/feross/queue-microtask

ryansolid commented 3 years ago

I see. I was trying to mimic the behavior of Vue Transition Group which seems to use setTimeout. I can see how this approach would be bulkier but honestly, I don't know all the use cases here so I've mostly been imitating. So for me to reconsider this I'd need to tread carefully. I am obviously interested where people have more experience and can explain why this behavior exists or when it is desirable. I am definitely interested in making this better but also not particularly versed in what that better looks like.

The way I see it the best path forward will be looking at the equivalent React and Vue examples and code to make some determinations. I might be missing some nuance here.

minht11 commented 3 years ago

I have tried to implement the same thing in react(no experience with Vue sorry) and it doesn't have same issues. React example: https://codesandbox.io/s/naughty-lichterman-lsmqs?file=/src/App.js Solid example: https://codesandbox.io/s/patient-wood-6vu4e?file=/index.js

The difference in timing could be attributed to the way solid renders and schedules DOM, but that's just speculation on my part. Reading up on queueMicrotask in MDN, it guaranties for code to run in specific order, before any other tasks are scheduled, just like Mutation Observer callback would. Inside previous standard discussion about it I also found this quote

setTimeout and rAF can cause UI flicker (rendering partially rendered UI)

which is exactly what is happening here, I am still not quite sure exactly how scheduling works, but it did fix animation flickering for me, but looking into more complex and varied use cases is the right decision before changing things up, there might be other unexpected things that come up.

Also issue seems to happen far less in Firefox, with simple animations it works normally 80% of the time, the more complex animation the more often it flickers. In Chromium flickering happens every time, I haven't tested Safari.