-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Popover: Avoid paint on popovers when scrolling #46187
Conversation
👋 Thanks for your first Pull Request and for helping build the future of Gutenberg and WordPress, @corentin-gautier! In case you missed it, we'd love to have you join us in our Slack community, where we hold regularly weekly meetings open to anyone to coordinate with each other. If you want to learn more about WordPress development in general, check out the Core Handbook full of helpful information. |
cd5046e
to
45ce6a9
Compare
@@ -2,6 +2,7 @@ $arrow-triangle-base-size: 14px; | |||
|
|||
.components-popover { | |||
z-index: z-index(".components-popover"); | |||
will-change: transform; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #46197 (comment) for a suggestion regarding how we add / remove this CSS property.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tyxla since the number of popover is limited I don't think this is a big issue, BUT it might actually not be needed since popovers seem to get a translateZ for free 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tyxla I have reverted the change since the translateZ does the job, however it seems to trigger repaint of some of the elements inside the block toolbar which is ... weird 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As @corentin-gautier mentioned, technically we shouldn't need it because of the translateZ()
value that framer motion already adds — in that sense, I didn't expect the browser to trigger repaints as reported in the previous message 🤷 although browser heuristics about when to create a new composite layer can change and evolve in time, so we're never really guaranteed.
Regarding the when we should add/remove this prop, it's worth mentioning that the Popover
component should be rendered only when the popover is actually visible — therefore, it seems OK to me that we keep that CSS rule as always ON: it's only rendered when the popover is open.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ciampo do you recommend i add it back then ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good if you could investigate a bit more into why removing will-change: transform
causes paint flashes in the toolbar, and see if we can achieve the desired result in any other way.
But if after the investigation the only guaranteed way to avoid paint flashes if by having will-change: transform
always applied, then yes — I would recommend you add it back at that point
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ciampo I looked into it yesterday but couldn't find the cause, it seems some of the svgs inside the toolbar trigger repaint when the toolbar position is updated ...
There are other tricks to avoid paint like using backface-visibility: hidden;
so that's an option too :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have we tried setting contain: paint
on the toolbar buttons, out of curiosity?
There are other tricks to avoid paint like using backface-visibility: hidden; so that's an option too :)
Yup, although that doesn't really change the fact that we'd be "forcing" the popover to be on its own composite layer — so will-change: transform
seems like a better (more semantic) choice
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ciampo using contain: paint;
is .... worse 😂 It triggers paint of all the buttons (I know it's very weird ahah)
Screen.Recording.2022-12-02.at.11.40.01.mov
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤷 Let's stick to wil-change: transform
then! Thank you for the investigation :)
If you ever feel like digging more into this and come up with more insights, I'm always eager to see how we can improve this component further!
// to use `translateX` and `translateY` because those values would | ||
// be overridden by the return value of the | ||
// `placementToMotionAnimationProps` function in `AnimatedWrapper` | ||
x: Math.round( x ?? 0 ) || undefined, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously, while animating we were accepting decimal values for x
and y
, and now we're rounding them. This is likely the reason for a bunch of e2e tests failing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tyxla Yes it was suggested by @ciampo here : #45545 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tyxla The tests indeed fail because of this but I have no idea how to change the expected values
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
npm run test:unit:update
should update the snapshots — you should then commit those changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ciampo I ran it but there nothing to commit 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mind rebasing and fixing conflicts? I'm currently unable to see that tests are failing, which makes it harder to make an informed suggestion 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tyxla I can see unit tests erroring because of the act
warning — do you mind helping out here? (I'm going to be AFK in the following weeks)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure thing! Happy to aid with that next week.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like the change here results in 0
values not being applied to update popover positions for popovers that are intended to be flush with the edge of the screen. I've opened up a potential fix over in #51320.
45ce6a9
to
6f05f45
Compare
Looks like this is making the toolbar a lot shakier when scrolling? |
Having paint flashing enabled + the element selected in the dev tools makes it shaky, Without this it behaves normally 🙂 |
Feels pretty solid to me: Screeny.Video.2.Dec.2022.at.09.43.26.movThank you for all these PRs! 👏 |
6f05f45
to
e4c3a32
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks and works well for me, thanks for the great work @corentin-gautier! 🚀
43c04a7
to
c253f6e
Compare
Before merging, do you mind adding a CHANGELOG entry for the changes in the We could actually add an entry also for #46197 which was merged without one |
@corentin-gautier tests appear to be failing for a few reasons here:
Let me know if that helps! |
7b7c6cb
to
3ca9e06
Compare
@tyxla Hum, yes there's a chance 😅 I now have the same result but not much more info ... |
@tyxla I can fix the test by using a rounding function on Something like this : const roundBoundingBox = (obj) => {
Object.keys(obj).forEach(k => {
obj[k] = Math.round(obj[k]);
});
return obj;
} But I don't know if this should be the way we fix this |
04697d0
to
4a57091
Compare
@tyxla thing is : if we round the position of the popover, then it will never be strictly equal to the position of the block (which is calculated with a getBoundingClientRect and will return sub-pixel values, https://playwright.dev/docs/api/class-locator#locator-bounding-box) From what I understand of the tests, their are testing that the dropzone (a BlockPopover) position is equal to the block (a paragraph) position. |
4a57091
to
02bbe89
Compare
Indeed, but then that points to a different problem - we either should change our expectations that the two positions will be equal (meaning, reconsidering the test completely instead of just rounding one of the values), or we should use the same heuristics - either both rounding or both non-rounding. Since rounding both is a no-go, should we reconsider the rounding for the popover position? |
As I mentioned before it was suggested by @ciampo here in reference to this
I think it's reasonable to assume that the values won't be exactly the same (and by that I mean rounded, so not far from the same) because as you said we can't round the block's position but rounding the popover's position seems to be required in order to get a sharp UI That being said it wasn't rounded before so maybe this could be the subject of another PR ? |
I'm inclined to agree with that. I'd love to get a second opinion from @mirka if possible. |
You're asking whether we should leave the rounding part out of this PR? I wouldn't be opposed to that, but also it looks easy enough to alter the test assertions so it has tolerance for subpixel differences. By the way, I think we could encapsulate the intent better if we explicitly tested for the tolerance, rather than apply rounding to the block values. So |
Loving that suggestion FWIW 👍 I'm happy to go with that - WDYT @corentin-gautier? With regards to the failing unit tests - @jsnajdr mentioned he has a branch that could fix them - would you like to try cherry-picking them to your branch and seeing if it fixes the tests? |
After #46429 is merged, you can rebase this PR on top of it and it should solve the failing unit tests (that test popover positioning). |
02bbe89
to
a198dfe
Compare
ac84df6
to
cfd40ae
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great! 💯 Thanks @corentin-gautier 🙌
A potential follow-up could be creating a custom inline matcher to make the assertion more eloquent, but that's not a big deal IMHO, since your comment is useful in making the intent clear.
I'll ship this for you 🚀
Thanks again and keep up the great work 🥇
What?
This PR changes the way popovers are positioned from top/left to translate(x, y) to avoid repaint on scroll
Why?
Changing the top/left properties triggers browser repaint which will result in poor performances
Testing Instructions
Fixes #45382
Screenshot
Before
Screen.Recording.2022-10-28.at.15.47.36.mov
After
Screen.Recording.2022-11-30.at.14.12.43.mov