Web Performance - Reducing Paint flashing on Amazon.com
That's a mouthful title alright !!
Problem Statement :-
If you're unfamiliar with terms like layout, paint and composition, I would recommend you to go through CRP link to get a know how so you can better relate with the solution ahead.
Alright, so how to first visualize this paint flashing stuff ?
To start with, let's go to amazon.com and there, we will take help of our age old friend DevTools :-
After opening the DevTools, lets do Ctrl/Command + Shift + P to open the Command Menu. Search for Show paint flashing rectangles and select that option.
Now if you try to interact with the left hamburger icon used to open/close the sidebar, you will see green flashing rectangles on the screen indicating paint pipeline is triggered. And it is this paint, we aim to eliminate.
Alright so now we visualize the problem and before I go on to explain the solution, you can also try arriving at the solution. Also, I want you to know that it took me 1.5 hours to identify the CSS modifications. You might take less or more time since that's all relative.
Did you try it ?
Yes/No ? (Drop in the comment section)
I identified two main elements that were responsible for this paint flashing :-
the CSS class
the sidebar element with id of
Consider the following CSS when sidebar is open :-
This is used by Amazon to prevent the scroll of page content when the sidebar is open. Now if we go to css triggers to see the layout, paint and composition cost of the same, here is what we will find :-
overflow-y together combined are equivalent to
overflow CSS property and as we can see a change in this triggers the layout pipeline making it an expensive operation.
If we remove, the
body.lock-position, you will notice that while closing the sidebar, there is no more paint flashing but while opening there still is (Obviously, now the when the sidebar is open, a user can scroll through page content but that was not a constraint). We will eliminate the leftover paint flashing next.
The result till now :-
Consider the following CSS when sidebar is closed :-
Consider the following CSS then sidebar is open:-
You will notice that
visibility CSS property initially takes a value of
hidden and on click of hamburger icon changes to
visible. Now let's go to css triggers to know what part of layout, paint and composition does
visibility trigger :-
Now in the bootcamp, there was a certain section where it was talked about how
transform CSS property is used to perform UI changes on a separate layer via the compositor thread and
will-change CSS property let's the browser know beforehand how an element is expected to change so it can promote the element to a separate layer as an optimization.
Let's look at how
transform works from css triggers:-
Cool lets use the above for the final piece of our solution :-
To mimic sidebar being closed, we can add
transform: translateX(-100%); to
#hmenu-container which will shift the whole container to left by 100% of it's width.
And to mimic sidebar being open, we can add
transform: translateX(0); to
#hmenu-container.hmenu-visible which will show the whole container in current viewport.
Here is the final result :-
Note:- The above will work even without
will-change:transform since that's an additional optimization of promoting
#hmenu-container to another layer before the sidebar is made to open.
And that's it for the solution. This challenge was fun because it integrated what we learned at the bootcamp. Also I think the other participants who completed the challenge might have had other approaches. So if you figure out some other way, do share the same in the comments 👇.