How I made Google’s data grid scroll 10x faster with one line of CSS
In my company, we use Google Search Console to check indexing status and optimize visibility of our websites. You can also check which external websites link to your page, and as I was browsing the “Top linking sites” page I noticed major scroll lag. This happens when choosing to display a larger dataset (500 rows) instead of the default 10 results.
As someone interested in frontend performance, I could not resist diving in to see if I could figure out why. After all, Google is pushing hard on web performance so one would expect them to set a good baseline in their own public facing apps 🤔
Step 1 — Recording a performance profile
Performance profiles are incredibly helpful in these cases, and just by viewing the report you can often clearly see why something has bad performance. So I opened DevTools / Performance
and started a recording, scrolled the list down a bit and then stopped the recording. This is what I saw:
Those red ears on the `Task` blocks indicate that something is taking longer than acceptable when scrolling. In general, you want to keep these blocks below 16 ms to achieve the ideal 60 FPS scrolling. In the image, the red eared blocks average about 150 ms, which translates to roughly 6–7 FPS. Come on Google, you can do better! 🐢
Step 2 — Figuring out what’s wrong
The timeline chart at the top shows how busy the CPU is with different types of tasks: orange for JavaScript, purple for layout and styles and green for painting. Here it is all purple, suggesting this is not a JavaScript issue but rather a DOM / styling issue:
This is confirmed in the waterfall chart below the CPU chart. It uses the same color coding and in most recordings it will have a lot of orange and a bit less purple & green. For this recording, it shows that time is mainly spent updating layers, as shown by the text in the purple blocks that says Update layer tree
:
Layers are created for scrolling content, translated content etc. Perhaps there are a lot of them? Let’s find out!
Step 3 — Checking those layers
Chrome DevTools includes an impressive amount of helpful tools, some of them more hidden than others. The Layers panel is one such hidden gem, to find it you have to hit the menu button in DevTools and pick More tools / Layers
. For my scenario it looks like this:
It does not have that many layers, but it does have a couple of huge ones. They seem to have content all the way down, leading to the conclusion that the datagrid used by Google does not use virtualized rendering. That explains part of it, but 500 rows are still not that many. There must be more to this…
Step 4 — Inspecting the DOM
Unfortunately, the DOM is not very performant when containing many elements. If it were, the virtualization techniques implemented in various popular JS data grids on the web would not be needed. An educated guess at this point is that the table is rendering a lot of elements. By setting up a Live expression on the DevTools Console you can click around in the elements panel and find out. Switch over to Console
, click the Create live expression
button (the eye) and type $0.querySelectorAll('*').length
.
Now when clicking around on the Elements
panel we see the following, first for the full grid:
As seen above it produces 16,000+ DOM elements to display just 500 rows, which is a bit excessive. Clicking on the body of the document, we see this:
The full page contains 38,000+ (!) elements, which is not how you build a fast web app! The obvious thing to do here would be to change to using a data grid with virtualized rendering, but let’s see if we can improve what is already there with less effort.
Step 5 — Improving the situation
Based on the data in the performance profile, I suspect that the entire page is laid out when you scroll the grid. And laying out that many elements is costly. If only there was a way to constrain the effects…
Good news — there is 😊 I tried applying some secret sauce, scrolled again, and now it felt much better. Which also clearly shows on this performance profile of it:
Each frame now takes around 16 ms, and we are scrolling at close to 60 FPS instead of 6–7. Amazing! 💪
So, what did I do? I simply added a single line of CSS to the <table>
on the Elements
panel, specifying that it will not affect the layout or style of other elements on the page:
table {
contain: strict;
}
As seen here:
That’s it, 10x faster with a single line of CSS. You can try this “fix” yourself in your own Google Search Console.
Learn more about the CSS contain
property over at MDN.
Shameless plug: If you’re in need of a performant data grid handling 100k+ rows with smooth scrolling, be sure to check out the Bryntum Grid (developed by me and my colleagues).