You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This bug report is about a performance issue in the implementation on stackoverflow.com, not about incorrect behavior. However it has a huge impact and is also easy to address with a simple change. I first considered using SO's internal feedback system, but found this repo to be a much better place for this kind of problem.
The problem
Due to how browsers (at least Chromium) process custom properties, using the universal selector when defining them on the html or body element slows down every recalculation by a factor of at least 2. On some complex pages I found it to make it take almost 4 times longer (~240ms vs ~60ms).
Consider the following performance recording of the home page:
Observe that, by far, most time is spent on rendering. In fact you're waiting much, much longer on rendering than on the network requests. Clearly this is the main bottleneck and any improvement to it directly translates to a faster page load. For all SO pages I tested, the vast majority of rendering tasks are style recalculations (e.g. the final large purple bar in the recording is a single style recalculation taking around 200ms).
I found that these recalculation times can be slashed in (at least) half, just by changing the following selector in primary.css
Removing the universal selector does not change the visual result, because every element still inherits the values from body. From my own experience I can assure that this is a change you can safely make, and I also confirmed on live pages that the second part of the rule is truly not needed.
Why is this so slow?
While I'm not fully sure about it, it's safe to say that using * to define custom properties puts the browser into a case that it's not optimized for at the moment. I guess it's not optimized as a pattern because it's not needed, since inheritance is exactly made to do this and enabled by default on custom properties.
While there's a chance that the slow performance is an oversight on the browser's end, if the pattern is truly unnecessary here then removing it seems the logical thing to do.
Expected improvement
As a simple POC, I downloaded a random answer page stripped of all scripts. I verified that the local copy had similar recalculation times as the original live page.
I then made another local copy of that page where the only difference is the aforementioned rule change in primary.css.
Here's a screenshot of the recordings side by side.
With the fix, time spent rendering went from 326ms to 194ms. A bit harder to see in the screenshots, every individual recalculation in this case was about 3 times faster (first one went from 94ms to 28ms).
That's over 100ms sliced off, and on the live page, which has more recalculations triggered by scripts, the improvement will be bigger, probably several hundreds ms on a desktop.
On lower end devices, I expect this improvement to be much bigger, even 1 second or more on big pages.
You can imagine how such an improvement will reflect in metrics like bounce rate.
Verifying this improves performance on every page
The simplest way to verify this is:
trigger a recalculation manually on any SO page and record using dev tools
You can run following snippet in the console right before pressing the record button:
reload the page so the snippet doesn't set the same value twice (you can also swap out the color to avoid reloading)
use dev tools to remove the second part of the rule as mentioned above (inspect any element to find this rule, it's a large list of striked through custom properties repeated for every parent element of any element)
run the snippet again and record
compare recalculation times in the recordings
The text was updated successfully, but these errors were encountered:
Inwerpsel
changed the title
Using universal selector (*) on custom property definitions causes all style recalculations on stackoverflow.com to take at least twice as long
Using universal selector (*) on custom property definitions causes all style recalculations on stackoverflow.com to take at least twice as long
Oct 17, 2024
The problem
Due to how browsers (at least Chromium) process custom properties, using the universal selector when defining them on the
html
orbody
element slows down every recalculation by a factor of at least 2. On some complex pages I found it to make it take almost 4 times longer (~240ms vs ~60ms).Consider the following performance recording of the home page:
Observe that, by far, most time is spent on rendering. In fact you're waiting much, much longer on rendering than on the network requests. Clearly this is the main bottleneck and any improvement to it directly translates to a faster page load. For all SO pages I tested, the vast majority of rendering tasks are style recalculations (e.g. the final large purple bar in the recording is a single style recalculation taking around 200ms).
I found that these recalculation times can be slashed in (at least) half, just by changing the following selector in
primary.css
to be only
On the StackExchange GitHub org I found a source sheet with the same pattern.
Removing the universal selector does not change the visual result, because every element still inherits the values from
body
. From my own experience I can assure that this is a change you can safely make, and I also confirmed on live pages that the second part of the rule is truly not needed.Why is this so slow?
While I'm not fully sure about it, it's safe to say that using
*
to define custom properties puts the browser into a case that it's not optimized for at the moment. I guess it's not optimized as a pattern because it's not needed, since inheritance is exactly made to do this and enabled by default on custom properties.While there's a chance that the slow performance is an oversight on the browser's end, if the pattern is truly unnecessary here then removing it seems the logical thing to do.
Expected improvement
As a simple POC, I downloaded a random answer page stripped of all scripts. I verified that the local copy had similar recalculation times as the original live page.
I then made another local copy of that page where the only difference is the aforementioned rule change in
primary.css
.Here's a screenshot of the recordings side by side.
With the fix, time spent rendering went from 326ms to 194ms. A bit harder to see in the screenshots, every individual recalculation in this case was about 3 times faster (first one went from 94ms to 28ms).
That's over 100ms sliced off, and on the live page, which has more recalculations triggered by scripts, the improvement will be bigger, probably several hundreds ms on a desktop.
On lower end devices, I expect this improvement to be much bigger, even 1 second or more on big pages.
You can imagine how such an improvement will reflect in metrics like bounce rate.
Verifying this improves performance on every page
The simplest way to verify this is:
You can run following snippet in the console right before pressing the record button:
The text was updated successfully, but these errors were encountered: