Web Performance - Reducing Paint flashing on Amazon.com

Web Performance - Reducing Paint flashing on Amazon.com

ยท

4 min read

That's a mouthful title alright !!

so mouthful

But this was a challenge which was organized at the end of a Web Performance Bootcamp held by team devkode (founder - Sunny Puri) on JavaScript Meetup (co-organizer NC Patro) platform. If you're interested in knowing my experience of the same, then here is the link but we will focus more on the challenge here.

Problem Statement :-

When you open and close the amazon.com sidebar, paint flashing occurs which can be eliminated via CSS modification. So you're required to identify those changes and submit the same.

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 :-

devtools pic

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.

Amazon_default_paint_flashing.gif

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)

Okay, here we go

I identified two main elements that were responsible for this paint flashing :-

  • the CSS class lock-position on body tag

  • the sidebar element with id of hmenu-container

body.lock-position

Consider the following CSS when sidebar is open :-

body.lock-position {
    overflow: hidden;
}

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-x-css-triggers

overflow-y-css-triggers

Both overflow-x and 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 overflow:hidden from 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 :-

Amazon_body_fix_paint_flashing.gif

#hmenu-container

Consider the following CSS when sidebar is closed :-

#hmenu-container {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    visibility: hidden;
    z-index: 100000;
}

Consider the following CSS then sidebar is open:-

#hmenu-container.hmenu-visible {
    visibility: visible;
}

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 :-

visibility-css-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:-

transform-css-triggers

Cool lets use the above for the final piece of our solution :-

#hmenu-container {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    will-change:transform;
    transform: translateX(-100%);
    z-index: 100000;
}

#hmenu-container.hmenu-visible {
    transform: translateX(0);
}

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 :-

Amazon_final_result.gif

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 ๐Ÿ‘‡.

P.S. - Btw if you're wondering about those slick looking keyboard keys support in markdown, check out this. Also the cover image is generated using this awesome web-app by Savio Martin.

Thank you for your time :D

Did you find this article valuable?

Support Lakshya Thakur by becoming a sponsor. Any amount is appreciated!

ย