question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Emotion causes large Layout Shift (with critical CSS extraction)

See original GitHub issue

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

image

After (deployed url | repo at commit):

image

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:

  1. Fork the repo and ensure you are at commit e44151d
  2. Run npm run build && npm run start
  3. 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.1
  • next version: 10.0.3
  • @emotion/react version: 11.1.1
  • @emotion/styled version: 11.0.0

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:3
  • Comments:11 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
neefrehmancommented, Dec 3, 2020

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.

CSS Strategy & Link to deploy Average latest layout shift
Linaria 360 ms
Emotion - out of the box critical extraction 950 ms
Emotion - out of the box critical extraction + @font-face fix 310 ms
Emotion - advanced critical extraction 400 ms
2reactions
Andaristcommented, Dec 2, 2020

I understand that this is not the perfect answer to your problem but a workaround for the issue seems to be this:

diff --git a/src/pages/_document.tsx b/src/pages/_document.tsx
index ef8dfa2..01e82ff 100755
--- a/src/pages/_document.tsx
+++ b/src/pages/_document.tsx
@@ -31,6 +31,14 @@ class MyDocument extends Document {
                     <meta property="twitter:title" content={title} />
                     <meta property="twitter:description" content={description} />
                     <meta property="twitter:image" content={imageUrl} />
+                    <style>
+                        {`@font-face {
+                            font-family: "Fleuron";
+                            font-weight: normal;
+                            font-display: block;
+                            src: url("/static/fonts/fleuronregular.woff2");
+                        }`}
+                    </style>
                 </Head>
 
                 <body>
diff --git a/src/styles/GlobalStyles.tsx b/src/styles/GlobalStyles.tsx
index 372ade2..52088a4 100644
--- a/src/styles/GlobalStyles.tsx
+++ b/src/styles/GlobalStyles.tsx
@@ -5,13 +5,6 @@ export const GlobalStyles = () => {
     const { colors } = useTheme();
 
     const globalStyles = css`
-        @font-face {
-            font-family: "Fleuron";
-            font-weight: normal;
-            font-display: block;
-            src: url("/static/fonts/fleuronregular.woff2");
-        }
-
         * {
             margin: 0;
         }

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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Emotion causes large Layout Shift (with critical CSS extraction)
Current behavior: I just migrated a project from Linaria to Emotion, but am seeing a massive increase in Cumulative Layout Shift, and I'm...
Read more >
Autoptimize + Critical CSS Cumulative Layout Shift CLS
I'm getting some cumulative layout shift between 0.20 – 0.9 and have been able to isolate it to the Autoptimize and Critical CSS...
Read more >
CSS | Everything I know - My Knowledge Wiki
Modern CSS Reset, Understanding Layout Algorithms & Defensive CSS are good reads. ... Critical - Extract & Inline Critical-path CSS in HTML pages....
Read more >
BEING EMOTIONAL DURING DECISION MAKING—GOOD ...
However, the nonsignificance of the path from positive emotion differentiation to affective influence regulation makes Hypothesis 4 only partially supported; ...
Read more >
Deferred non-critical caused high CLS - Stack Overflow
Under the Google "PageSpeed Insights" for the page, look under the section "Diagnostics", and expand the sub-heading "Avoid large layout shifts" ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found