Gutenberg: Block & toolbar "vibration" during moving animation

Created on 11 Mar 2020  路  14Comments  路  Source: WordPress/gutenberg

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

[Status] In Progress [Type] Bug

All 14 comments

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.

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.

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?

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.

@youknowriad when you have a breather, I'd love your thoughts on https://github.com/WordPress/gutenberg/issues/20793#issuecomment-598053929.

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?

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.

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.

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.

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.

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

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

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.

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.

Was this page helpful?
0 / 5 - 0 ratings