Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

ng-animate border-spacing causes slight jump when animating #5255

Closed
scottopherson opened this issue Dec 4, 2013 · 13 comments
Closed

ng-animate border-spacing causes slight jump when animating #5255

scottopherson opened this issue Dec 4, 2013 · 13 comments
Assignees
Milestone

Comments

@scottopherson
Copy link

While I was messing around with the ngAnimate module in the 1.2.3 release I noticed slight "jumps" in some of the elements I was animating, but not all of them. After some digging I realized that the jump in these particular elements was being caused by border-spacing: 1px 1px being applied to them during the animation. I created a small demo that demonstrates the behavior I was seeing:

http://jsfiddle.net/47E8m/1/

After some googling, I came to this issue thread and then realized that the jumpy elements I had were all utilizing the clearfix hack which uses display: table.

Without having to modify any of my other CSS, a quick workaround I found was to add the following to my CSS:

.ng-animate { border-collapse: collapse; }

@matsko what's the nasty bug that makes clip or border-spacing necessary? Perhaps there's some other CSS properties we could try.

@seanzx85
Copy link

seanzx85 commented Dec 4, 2013

+1
This caused a pretty nasty visual jump of my content. It added the 1 pixel border to multiple divs causing the last div to render off the screen, and then snap back half way through the transition.

@dcartertwo
Copy link

+1 Also have seen this issue.

@matsko
Copy link
Contributor

matsko commented Dec 4, 2013

Hey guys.

So the border-spacing CSS feature is here to ensure that all transition animations eventually close incase invalid or incomplete CSS code is in use. Let's say we have an ng-enter animation that looks like so:

.my-animation {
   transition:1s linear all;
}
.my-animation.ng-enter {
   opacity:1;
}
.my-animation.ng-enter.ng-enter-active {
   opacity:0;
}

This works fine, but since the transition is placed on the root CSS class, .my-animation, this means that when a leave operation happens a transition will be issued for .ng-leave. $animate will assume a transition has been triggered, add the first CSS class (.ng-leave) and then the second one after the reflow (.ng-leave-active), but the animation will never end because nothing has changed in the styling because there are no styles to apply to the element. This would cause the elements that are supposed to leave on the page to not get cleaned up and hang out forever and this ends up being a nasty bug which is hard for the developer to deduce to it being problematic CSS code. border-spacing (and prior to that clip) handled this trick and border-spacing is nice because it only shows up if you have a table (or something with display = table) being animated (and how often does that occur?). But it seems like there is no magical CSS class that handles the action without it causing a flicker (in this case if you have a display of table).

The ideal solution would be to scrap using an extra CSS property and instead use a global timeout that flushes all pending animations after X number of milliseconds after the total time of the transition has passed. The only issue is that it may cause an animation to end early since browsers sometimes start animations a few 100ms later. The main issue is that we would have to make the closing timeout to be very long and that wouldn't help close transitions as soon as the animation itself is done.

For now, to get around the jumpy flicker, just put this in your code (use AngularJS 1.2.3):

/* .container is the CSS class from the plunkr example.
    Use that one or replace with the CSS class which contains
    the element that is a table which will render the border-spacing */
.container.ng-animate-start,
.container.ng-animate-active {
  border-spacing:none;
  -ms-zoon:auto;
}

@seanzx85
Copy link

seanzx85 commented Dec 4, 2013

@matsko thanks for the explanation, and code.

@scottopherson
Copy link
Author

Gotcha @matsko, makes sense; that would be a nasty bug to diagnose. Thanks for the info (and for all the work on ngAnimate btw, loving it).

it only shows up if you have a table (or something with display = table) being animated (and how often does that occur?)

Might happen often though, no? Tables are used often and the element being animated doesn't necessarily need to be a table (or use display:table) for the issue to occur; simply animating an element containing a table (or element using display:table) can cause some flickering due to the border-spacing being cascaded down from the animated container. I updated the demo to show the flicker occurring when a container doesn't use display:table but simply has a table child inside it:

http://jsfiddle.net/47E8m/2/

Not a huge issue though since we have both come up with some workarounds, but I could see it causing headaches for some developers in the future.

@matsko
Copy link
Contributor

matsko commented Dec 4, 2013

Ahh, I didn't think border-spacing is inherited. Alright, I'll need to investigate to see if there is another property (which I doubt). One solution is to use outline-width, but delegate to something else if the element already contains an outline.

This back and forth with checking for styles does make ngAnimate/animate.js messy and a pain to deal with. Perhaps it's best to fallback to a global timeout.

@ghost ghost assigned matsko Dec 4, 2013
@paldepind
Copy link

If a global timeout if what it takes to fix this I think that's what should be done. Once identified this issue is simple to fix by adding border-spacing: 0; but getting to that point is pretty painful.

Animations are typically fast and then the artifacts of the increased border spacing shows up as nothing more but a quick but very nasty flicker. It furthermore makes it hard to use the HTML element inspection tools in browsers to figure out what's going wrong. It at least took me some time to debug the problem and figure out that AngularJS was adding border spacing.

And this problem isn't only affecting people doing animations with elements containing tables. I'm using the Bootstrap grid system and here the border spacing also shows up (which further makes the debugging tricky since I'm not even using tables).

@scottopherson
Copy link
Author

@paldepind yeah it affects the Bootstrap grid system because the rows in the grid use clearfix (display:table). I don't know the original problem or source code well enough yet to declare whether or not a global timeout is the way to go but the current border-spacing solution clearly has a lot of negative effects.

@matsko
Copy link
Contributor

matsko commented Dec 13, 2013

Yup. border-spacing was a bad call. Moving onto the timeout fix. It won't make it for tomorrow's 1.2.5 release, but it will be there for 1.2.6.

@scottopherson
Copy link
Author

@matsko you're awesome.

@paldepind
Copy link

@matsko Sounds good!

matsko added a commit to matsko/angular.js that referenced this issue Dec 14, 2013
…y to close transitions

With ngAnimate, CSS transitions, that are not properlty triggered, are forceably closed off
by appling a fallback property. The fallback property approach works, however, its styling
itself may effect CSS inheritance or cause the element to render improperly. Therefore, its
best to stick to using a scheduled timeout to run sometime after the highest animation time
has passed.

Closes angular#5255
@matsko
Copy link
Contributor

matsko commented Dec 14, 2013

Special delivery: #5403

matsko added a commit to matsko/angular.js that referenced this issue Dec 17, 2013
…y to close transitions

With ngAnimate, CSS transitions, that are not properlty triggered, are forceably closed off
by appling a fallback property. The fallback property approach works, however, its styling
itself may effect CSS inheritance or cause the element to render improperly. Therefore, its
best to stick to using a scheduled timeout to run sometime after the highest animation time
has passed.

Closes angular#5255
matsko added a commit to matsko/angular.js that referenced this issue Dec 17, 2013
…y to close transitions

With ngAnimate, CSS transitions, that are not properlty triggered, are forceably closed off
by appling a fallback property. The fallback property approach works, however, its styling
itself may effect CSS inheritance or cause the element to render improperly. Therefore, its
best to stick to using a scheduled timeout to run sometime after the highest animation time
has passed.

Closes angular#5255
Closes angular#5241
Closes angular#5405
@arush
Copy link

arush commented Dec 17, 2013

Awesome thanks for this @matsko

matsko added a commit to matsko/angular.js that referenced this issue Dec 19, 2013
…y to close transitions

With ngAnimate, CSS transitions, that are not properlty triggered, are forceably closed off
by appling a fallback property. The fallback property approach works, however, its styling
itself may effect CSS inheritance or cause the element to render improperly. Therefore, its
best to stick to using a scheduled timeout to run sometime after the highest animation time
has passed.

Closes angular#5255
Closes angular#5241
Closes angular#5405
@matsko matsko closed this as completed in 54637a3 Dec 19, 2013
jamesdaily pushed a commit to jamesdaily/angular.js that referenced this issue Jan 27, 2014
…y to close transitions

With ngAnimate, CSS transitions, that are not properlty triggered, are forceably closed off
by appling a fallback property. The fallback property approach works, however, its styling
itself may effect CSS inheritance or cause the element to render improperly. Therefore, its
best to stick to using a scheduled timeout to run sometime after the highest animation time
has passed.

Closes angular#5255
Closes angular#5241
Closes angular#5405
jamesdaily pushed a commit to jamesdaily/angular.js that referenced this issue Jan 27, 2014
…y to close transitions

With ngAnimate, CSS transitions, that are not properlty triggered, are forceably closed off
by appling a fallback property. The fallback property approach works, however, its styling
itself may effect CSS inheritance or cause the element to render improperly. Therefore, its
best to stick to using a scheduled timeout to run sometime after the highest animation time
has passed.

Closes angular#5255
Closes angular#5241
Closes angular#5405
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
6 participants