Emotion’s default SSR rendering inserts <style> tags in the HTML body above each element being styled by an inline css (or sx) prop. This means that, until the React app loads and the browser re-renders the page, there are a number of extra elements in the DOM that the developer didn’t expect. Even though they’re themselves invisible, they disrupt any :first-child or * + *–type selectors in the CSS.
If the site uses those selectors, it can lead to a flash of the page’s content moving around as everything loads.
This is a known issue with Emotion 10’s zero-configuration SSR implementation: emotionjs/emotion#1178
As mentioned in the bug, gatsby-plugin-emotion could eliminate this problem, either by default or as an option, by using Emotion’s other SSR API, extractCritical.
You can see these elements easily on the Theme UI homepage by turning off JavaScript in devtools and inspecting the DOM:

(Though that site does not obviously use the type of selectors that these rogue elements disrupt.)
Emotion 10’s default SSR has two primary advantages: no special configuration, and support for React’s streaming rendering mode. Because Gatsby lets us distribute built configurations, and because it pre-renders complete HTML pages, neither of the Emotion 10 advantages is particularly compelling.
By switching to use extractCritical, Gatsby would eliminate the surprise that comes from these elements that do not appear in develop mode and can cause page loading to be unnecessarily jumpy.
While this should go by unnoticed by most users of gatsby-plugin-emotion, there is the potential for conflicting with sites that are already using the SSR hooks. Therefore it might be worth making this SSR rendering strategy an option rather than the default.
I’d be willing to try and implement this, if folks feel like it could be accepted.
@fionawhim I've been experiencing this issue as well when using gatsby-plugin-emotion together with Typography.js in my site's global reset stylesheet.
I'd like to see the plugin gain a way to use the extraCritical SSR API to work around this problem, and I'd be happy to take a shot at adding it as I'd like to contribute something back to Gatsby – unless of course you've already made a start!
@greenie Feel free to take a crack at it, either getting a PR merged here or as a separate plugin.
I was able to get this working for my blog’s theme. You can see my approach in the gatsby-ssr.tsx and gatsby-browser.tsx files.
As commented in the closed PR we want our plugins to default to whatever the core library does. In this particular case I'd also say that these kind of selectors are problematic itself. Feel free to publish this as a plugin or blog post. Thanks!
@LekoArts Thanks for taking the time to look at this PR. I appreciate that the goal of plugins is to keep them simple and to default to the underlying library's behaviour.
I do agree with @fionawhim's point that Gatsby doesn't benefit hugely from Emotion's zero-config SSR API, hence the motivation to provide an option to use extractCritical instead. It would give the user a principle of least astonishment experience when writing styles with Emotion, and prevent repaints in the user's browser after Emotion kicks in an hoists the inline style tags to the head of the page.
That being said if there's a strong enough feeling that this shouldn't be in gataby-plugin-emotion, I'm happy to create a seperate one that uses it instead.
Most helpful comment
@LekoArts Thanks for taking the time to look at this PR. I appreciate that the goal of plugins is to keep them simple and to default to the underlying library's behaviour.
I do agree with @fionawhim's point that Gatsby doesn't benefit hugely from Emotion's zero-config SSR API, hence the motivation to provide an option to use extractCritical instead. It would give the user a principle of least astonishment experience when writing styles with Emotion, and prevent repaints in the user's browser after Emotion kicks in an hoists the inline style tags to the head of the page.
That being said if there's a strong enough feeling that this shouldn't be in
gataby-plugin-emotion, I'm happy to create a seperate one that uses it instead.