metafizzy / outlayer

:construction_worker: the brains & guts of a layout library
163 stars 63 forks source link

Regression: outlayer 1.1.8 animates elements incorrectly #3

Closed Aintaer closed 8 years ago

Aintaer commented 11 years ago

Since at latest 1.1.8, outlayer started reflowing elements by animating them correctly at first, but then suddenly shifting element locations mid-animation, finally moving them into their correct positions.

I wish I could record the transition effect, but it's difficult to capture.

Aintaer commented 11 years ago

http://youtu.be/WYBSJkudxNs Tried to capture what it does in video.

MarvinJanssen commented 10 years ago

I came here to report an issue with a sort of jerking movement, but it looks like you are suffering from the same problem, so I will post it here instead.

I suspect that you have a transition property set in css for your items, is this correct? If so, try removing it and see if that fixes your problem.

I'll try and explain in short what is happening:

Outlayer uses css3 transforms along with a transition to animate the movements. It adds these properties on the fly and removes them after the animation end. Now, you know that if you transition a property (say, the colour), and then change the colour on hover, it transitions to it, and back when you no longer hover it. This is the same thing that happens here: Outlayer adds a translate3d transform, which is also transitioned, and after this transition is complete, it updates the location and removes the transform and the transition property. However, since you have a transition property added for the transform property in css, the 'undoing' of the translate3d is transitioned as well. If we follow the process step by step:

This is why you see it move to the final position, then jump to a position beyond that, relative to the distance between the original position and the final position, and then move back to the final position. It took me quite a while to figure this out, and to come up with a way to fix it.

To fix this, Outlayer should set the transition property to 'none', then remove the transform property, and then remove the transition property.

I have prepared this fiddle to illustrate the problem, and included a temporary fix:

http://jsfiddle.net/FfzAC/1/

You should be able to copy the packery_transition_duckpunch() function to your project, but note that this is a rather crude fix. It overwrites a function inside item.prototype.

Hope this helps you until it is properly fixed. Please note I only tested it in Safari, Chrome Canary, and Firefox.

desandro commented 10 years ago

@MarvinJanssen Thanks so much for digging into this

I agree. The most likely cause is a transition style on items that affects how Packery cleans up after doing its own transitioning. Your duck-punch is a valid solution, and I recommend it (although a bit of an ugly one, but that's my fault. I apologize for making you go into that part of the code. It's a mess.)

Another solution is to use another element only for the hover transitioning, so it doesn't affect the transition on the item.

Or, add a class when transition that overrides the CSS transition. See http://codepen.io/desandro/pen/anHgr

It's still not pretty, but it's great that the problem has been identified.

MarvinJanssen commented 10 years ago

@desandro Glad I could help! The erratic behaviour stumped me, but removing the transition property in the css was no option for me. Thus, I reserved a few hours to try and find where it came from.

The first function I duck-punched was item.css(), what threw me off was the fact that the translate3d transform was added by it, but not removed (and I later found out it was done directly inside ontransitionend). I don't know if this is a mistake or if it proper behaviour?

I like your solution a lot. It's a lot less intrusive than the one I came up with. I might adapt it for my project for now. I also like how it gives you a new opportunities when it comes to styling the items. Perhaps a new setting transitioningClass is in order?

I only just noticed that the fix I gave in my example is still using Packery.prototype, rendering it useless for other Outlayer implementations. I updated the example for brevity: http://jsfiddle.net/FfzAC/2/

desandro commented 8 years ago

Closing this old issue.