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.

The “Top linking sites” section in Google Search Console, 500 rows per page

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:

Performance profile for scrolling the “Top linking sites” data grid, very low FPS

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:

Chart shows that CPU is busy handling layout

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:

Waterfall chart shows that “Update layer tree” is what makes scrolling slow

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:

The “Layers” panel in Chrome DevTools, layer filled with content all the way down

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:

Live expression showing descendant element count for the selected element

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:

A lot of elements!

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:

Scrolling much improved!

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).

JavaScript developer focused on UI and performance