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.

Problems surrounding SSR injection of <style> and unreliability of :first-child selectors

See original GitHub issue

Problem description:

In emotion v10+, a new warning is thrown if you use :first-child, :nth-child, or :nth-last-child selectors in a styled component or css prop value. This is because, when using SSR, the style element is injected immediately above (prepended) the associated component. (More details.)

There are a number of problems with this approach:

Note: I made a test case demo to illustrate which selectors are unreliable.

  1. In our codebase and matching years of experience for myself and peers, the “first” selectors are used much more often than the “last”. Making these selectors unreliable is a big blow to those expecting standard CSS features to work.
  2. The suggested workaround of changing, e.g. :first-child to :first-of-type, only works if all sibling elements are of the same type. This is probably fairly common for components like lists, grids, etc… But it’s far from a guaranteed solution. It could also discourage the use of semantic markup by driving devs to “just use divs” for everything, since it’s a simpler “fix”.
  3. The list of unsafe selectors is incorrect.
    • The adjacent sibling pattern, * + [anything], is unreliable, but not listed.
    • :only-child is unreliable, but not listed.
    • :nth-last-child is still reliable when prepending the style element and should not be listed.
  4. Consumers not interested in SSR should be able to turn off the warning (#1105)

Suggested solution:

Let’s tackle each problem, in turn:

  1. “First” vs. “last” selectors (or prepending vs. appending the style element)

    If emotion injected the style element after (appended) the associated component, then the following selectors would be unreliable: :last-child, :nth-last-child, :only-child.

    Compare that to the currently unreliable selectors: * + [anything], :first-child, :nth-child, :only-child.

    By changing to appending the style element, emotion would no longer block use of the common adjacent sibling selector and the “last” (rather than “first”) varieties of the selectors would be affected, which I would argue is a better tradeoff more in line with actual usage of each [citation needed].

  2. “of-type” workaround

    The warning’s suggestion should be reworded to make clear that it may not work in all scenarios.

  3. Incorrect unsafe list of selectors

    • :only-child needs to be added (changing this to :only-of-type is a good workaround, though!
    • If the style element remains prepended
      • The * + [anything] selector pattern needs to be flagged
      • :nth-last-child needs to be removed
    • If the style element is appended
      • Update list to include selectors in (1), above.
  4. Mute the unsafe selectors warning

    At the very least, emotion should allow consumers to do so.

Alternative solutions:

Another suggested workaround is to somehow replace :first-child selectors with :first-child:not(style), style:first-child + * in the styles output. While a clever bit of CSS selecting, this suggestion has two main problems I can think of: 1) it won’t work for non-:first-child selectors (though maybe we could come up with other rewrites for the others) and 2) replacing :first-child in a selector is not trivial, as it is affected by whether or not its used on the immediate element being styled or a descendent element.

The maintainers of emotion and its community could also simply decide that making these selectors unreliable is not worth the tradeoff of SSR “just working” and abandon the approach of injecting colocated style elements entirely. I have no idea how palatable such a change would be, but wanted to enumerate all the options.


This issue is intended to open discussion around these problems. If we can decide on forward actions, I’m happy to help implement wherever I can.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:65
  • Comments:63 (35 by maintainers)

github_iconTop GitHub Comments

17reactions
brentertzcommented, Feb 1, 2019

Hello everyone. Just weighing in with some comments and questions…

I appreciate the simplicity and relative elegance of Emotion’s SSR strategy, but I believe that the trade-off of “breaking” many commonly used CSS pseudo selectors to not be worth it.

Some pseudo selector usages can be changed to an alternate, but oftentimes there are others that get unwieldy fast or simply cannot be accommodated. In any of the cases, the updated implementations are unlikely to be the best choice or most easily understood. Further, the console error that suggests to try using nth-of-type is also not very helpful, particularly for those not even doing SSR. #1105.

May I ask what was the impetus to change from the previous SSR implementation? Performance, reliability, usability, difficulty, maintenance? I did not use it and therefore only have so much perspective on it. It seems that if it did not suffer from these issues, that perhaps it was a superior solution, albeit perhaps less elegant. Personally speaking, I would much rather have to deal with a bit of extra SSR configuration code as it is often a one time cost and limited in scope.

Is it possible to opt-out of the new SSR implementation for those cannot accommodate the concessions? I see that it is documented that the old SSR API’s can be used with Emotion 10, however with the caveat that is should only be done for compatibility and migration purposes. I can’t imagine that you would want to support multiple API’s long term though. It also would not address #1105.

A few comments on some of the other proposed ideas…

  • Browser support and accessibility are paramount concerns.
  • I don’t believe rewriting selectors to be a good idea. It seems potentially error prone, slow, heavy-handed, unexpected, and likely confusing to debug.
  • Regarding an inline script insertion to move styles, I am not sure that I fully grok the suggestion. Is it one script tag per page or per component? If per component, it should ideally remove itself to avoid breaking any pseudo selectors. If once per page, would the script or function call need manually inserted by users in their server layout code? I suppose either of these sounds potentially viable, though I am unaware of what the performance costs might be and what rendering oddities might arise on slower connections.
9reactions
maximilianschmittcommented, Feb 7, 2019

I don’t think rewriting selectors is a good idea because it’s confusing when debugging and also complex and error-prone.

The server-rendering of Emotion 10 unfortunately also messes up the following selector:

> * + * { margin-top: 5px; }

I agree with @brentertz that sacrificing common CSS selectors for easier setup is not worth it. At least not for us.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Bootstrap: The pseudo class “: first child” is potentially ...
Problems surrounding SSR injection of <style> and unreliability of :first-child selectors. Problem description: In emotion v10+, a new warning ...
Read more >
Frontend Handbook | React / Common SSR errors - Infinum
Since the first child is a <style> instead of a <p> element, the :first-child selector won't work. Solution. Use :first-of-type , :last-of-type ...
Read more >
Styled components SSR concerns when using nth-child and ...
Emotion's SSR has issues like FOUC when using some css selectors (e.g ... (see Problems surrounding SSR injection of and unreliability of ......
Read more >
first-child - CSS: Cascading Style Sheets - MDN Web Docs
The :first-child CSS pseudo-class represents the first element among a group of sibling elements.
Read more >
emotionで:first-child がエラーになる - k.log
Problems surrounding SSR injection of style and unreliability of :first-child selectors #1178. エモーションv10 +では、スタイル付き ...
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