Emotion causes large Layout Shift (with critical CSS extraction)
See original GitHub issueCurrent behavior:
I just migrated a project from Linaria to Emotion, but am seeing a massive increase in Cumulative Layout Shift, and I’m not sure why. I’m using Next.js and can confirm that the “out of the box” critical CSS extraction is working fine after looking at the HTML output. It’s my understanding that this should reduce layout shift as the styles will load before paint.
Inspecting the network panel shows a small increase in bundle size, but the performance panel shows hugely elongated period of layout shift (seen in light red below). To my eye it looks like there’s a re-painting of all the CSS upon rehydration, which causes a flicker.
Before (deployed url):
After (deployed url | repo at commit):
Using devtools’ break on subtree modifications
I can see that the SSR styles are initially in a style tag inside Next’s App container element in the body
(above the other dom content). Then they are deleted from their place and placed in the head
, which looks to be what’s causing the shift. It seems like the styles should already be placed in the head during the SSR process, and not have to be moved later?
To reproduce:
- Fork the repo and ensure you are at commit
e44151d
- Run
npm run build && npm run start
- Refresh the homepage to see the layout shift occur
Expected behavior:
The page should load, being render-blocked by the critical css, and then painting to the screen without any subsequent layout shift or style changes.
Environment information:
react
version: 17.0.1next
version: 10.0.3@emotion/react
version: 11.1.1@emotion/styled
version: 11.0.0
Issue Analytics
- State:
- Created 3 years ago
- Reactions:3
- Comments:11 (4 by maintainers)
Top GitHub Comments
Since I’ve attempted a few different ways of CSS extraction I thought I’d put a bit more rigour into a test. Here are the links for each strategy as well as a (roughly calculated) average latest layout shift from the performance panel.
360 ms
950 ms
@font-face fix
310 ms
400 ms
I understand that this is not the perfect answer to your problem but a workaround for the issue seems to be this:
For some reason, this font is causing a layout shift - when the rule for it is temporarily removed from the DOM. Usually, this doesn’t cause any problems - this is the very first report about this problem and I haven’t encountered it in the past.