Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block & toolbar "vibration" during moving animation #20793

Closed
ellatrix opened this issue Mar 11, 2020 · 14 comments · Fixed by #22640
Closed

Block & toolbar "vibration" during moving animation #20793

ellatrix opened this issue Mar 11, 2020 · 14 comments · Fixed by #22640
Assignees
Labels
[Status] In Progress Tracking issues with work in progress [Type] Bug An existing feature does not function as intended

Comments

@ellatrix
Copy link
Member

ellatrix commented Mar 11, 2020

It's been brought to my attention that the block toolbar vibrates a bit when you move a block up and down. At first this might seem like it is caused by moving the block toolbar to a popover, but this is not really true. The G2 added much more contrast to the block toolbar, making the vibration more visible. As you can see in the following video, a block that I styled just like the toolbar vibrates just as much as the toolbar itself.

block-vibration-contrast

So what is the problem? The block moving animation sets a sub pixel position to the block, which first of all will make it look slightly blurred than when at a whole pixel position. I think @jasmussen knows more about the specifics of this. Secondly, at the same time we are scrolling the page, making it seem like the block stands still relative to the viewport. Scrolling can only happen at whole pixel positions, not at sub pixel positions.

So on the one hand we have sub pixel movement (of the block), and on the other hand we have whole pixel movement (when scrolling). You can see how this might make it look like it vibrates. The block (and block toolbar) blurring at sub pixel position will only make it look worse. lines might suddenly appear thinner or thicker. When you add more contrast and horizontal lines, it becomes even more visible.

I'm not sure how we can solve this, but here's two ideas:

  • We don't animate at sub pixel positions. This might make the animation feel less smooth. :/
  • We try to do some magic and keep the block exactly in the same position relative to the viewport, so the only "moving" parts are the scrolling and maybe the rest of the blocks. This is similar to the first point, only that the block won't visibly move at all.

Cc @mtias @youknowriad @jasmussen

@ellatrix ellatrix added the [Type] Bug An existing feature does not function as intended label Mar 11, 2020
@ellatrix
Copy link
Member Author

An easy way to play with this is by moving the image placeholder blocks (which looks like a big toolbar). Then focus on the horizontal outline.

@ellatrix
Copy link
Member Author

I'm not going to spend time on this problem for now, cause it's not super horrible to me, but let me know if it is actually worth to explore further.

@jasmussen
Copy link
Contributor

I've noticed this. While it's not something I think about a lot, it would be nice if we could refine this.

As you note, this appears to be an image that actually starts with the animation on the block itself. One might hope that if that animation can be "fixed", the block toolbar behavior would follow suit.

Here's what I seen in the DOM when I move a block:

vibrating

As you can see there's a recurring translate that keeps updating for each pixel moved. I'm almost certain that this is the cause of the vibration. Translate is the correct animation property to use because it renders on the GPU, but when the entire duration of the animation is animated like this, we are actually bottlenecked on the animation frame/screen framerate/sync of the two.

I understand why this happens: we are actually moving the block, literally in the DOM, we can't just apply a destiation-translate, and then let transition handle the in-betweening.

Or can we? Because this would be the correct thing to do.

When you update the translate property ONCE, then let transition handle the in-betweening, we are offloading all the hard work to the browser rendering engine and the GPU. In my experience, this is rock solid.

What happens when we move a block?

  1. User clicks "down" to move the block.
  2. The block is moved in the DOM instantly.
  3. A translate the distance the block is travelled is applied, and then counts down until it reaches zero. The same happens for the two blocks immidately before and after the block being moved.

So essentially the translate keeps the block in its own place and then animates towards the destination.

How can we rethink this so that it uses transition, instead of having the translate be updated by JS?

One idea. All blocks have a transition: translate 0.2s ease;, and then:

  1. User clicks "down" to move the block.
  2. A translate is immediately applied that shifts the block to where it will be.
  3. The transition lasts 0.2s. A JS timer moves the block in the DOM, and removes the translate property after the 0.2s have completed.

Would this work?

@jasmussen
Copy link
Contributor

Incidentally, that's how I animate things on my website:

animation

The GIF here does not capture the framerate, so I invite you to visit the website directly to see that the animation is as smooth as it needs to be. But you can see from the GIF that on click, the destination properties are immediately applied, and the transition then handles the animation.

@jasmussen
Copy link
Contributor

@youknowriad when you have a breather, I'd love your thoughts on #20793 (comment).

@youknowriad
Copy link
Contributor

User clicks "down" to move the block.
A translate is immediately applied that shifts the block to where it will be.
The transition lasts 0.2s. A JS timer moves the block in the DOM, and removes the translate property after the 0.2s have completed.

I feel like this is already what we do unless I'm not understanding something?

@jasmussen
Copy link
Contributor

What we are doing now is apply a translate that moves the block to where it was, which necessitates the translate property continuously using js.

If what we could do instead is apply a single static translate that moves the block visually, apply a transition to make it animate, and then use JS to move the block after the animation is complete, then m we wouldn't need to continuously update the translate property.

It's the updating of translates that I believe is causing the vibration.

@youknowriad
Copy link
Contributor

use JS to move the block after the animation is complete

Why do you need to move the block once the animation is complete? Shouldn't it be already at the right position?

So you're saying, trying to avoid the use of react-spring for this animation and rely on CSS. It could work but I can't guarantee without trying.

@ellatrix
Copy link
Member Author

We can certainly try a pure CSS animation, but I'm not 100% sure if it will solve the problem. Part of the problem is that there's two moving parts: the block and the scroll position. We're allowing the block to move at sub pixel positions, while at the same time, we cannot move scroll position by the same amount. We move scroll position at a rounded value. I believe this is the source of the vibration.

@jasmussen
Copy link
Contributor

I don't know if we can use my website as a prototype, because it's probably comparing apples to oranges. But the behavior there is to set a static translate and let the transition inbetween.

@ellatrix
Copy link
Member Author

@jasmussen Right, I understand how you're animating there, but there's no vertical animation + vertical scroll going on at the same time?

@jasmussen
Copy link
Contributor

There isn't, no. Do you believe it's the scrolling that's causing the vibration?

@ellatrix
Copy link
Member Author

I believe it's the visual result of moving the block at sub pixel positions and scrolling the page at the same time at whole pixel positions. This is done to make it seem like the block is standing still relative to the viewport.

@ellatrix
Copy link
Member Author

So a solution may be to make sure the block stands still at whole pixel positions relative to the viewport. I can have a look at this when I have more time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Status] In Progress Tracking issues with work in progress [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants