styled-components: Server Side Rendering: First paint missing some styles (FOUC)
Environment
System:
- OS: macOS High Sierra 10.13.5
- CPU: x64 Intel® Core™ i5-4308U CPU @ 2.80GHz
- Memory: 82.71 MB / 8.00 GB
- Shell: 3.2.57 - /bin/bash
Binaries:
- Node: 8.9.4 - ~/.nvm/versions/node/v8.9.4/bin/node
- npm: 6.1.0 - ~/temp/Martin/metrics-dashboard/node_modules/.bin/npm
- Watchman: 4.7.0 - /usr/local/bin/watchman
npmPackages:
- babel-plugin-styled-components: ^1.5.1 => 1.5.1
- styled-components: ^3.2.6 => 3.2.6
Reproduction
The chunk of server side rendering code used:
const sheet = new ServerStyleSheet()
let html = ReactDOMServer.renderToString(sheet.collectStyles(
<Provider store={store}>
{<RouterContext {...renderProps} />}
</Provider>
))
const styleTags = sheet.getStyleTags() // or sheet.getStyleElement()
My index template (index.ejs) as such:
<!DOCTYPE html>
<html>
<head>
<%- styleTags %>
</head>
<body style="margin: 0; font-family: 'PT Sans', Arial;">
<div id="root" style="height: 100%;">
<%- html %>
</div>
<script type="text/javascript" charset="utf-8">
window.__REDUX_STATE__ = '<%= reduxState %>';
</script>
</body>
</html>
And just in case some styled-component code, though I don’t expect this to be the issue (possibly because of using extend?).
// H1.js file
import styled from 'styled-components';
const H1 = styled.h1.attrs({ className: 'h1' })`
font-size: 4rem;
`;
export default H1;
// end of H1.js file
// WidgetTitle.js file
import NormalH1 from "components/H1";
const WidgetTitle = NormalH1.extend.attrs({ className: 'widget__title' })``;
export default WidgetTitle;
// end of WidgetTitle.js file
Steps to reproduce
- Server side rendering set up as shown above, following closely the steps here: https://www.styled-components.com/docs/advanced#server-side-rendering.
Expected Behavior
For all styles to be applied during first paint (like so below).

Actual Behavior
Only some styles being applied on first paint, while some rules (specifically font-size) seems to be applied only after the JS bundle is parsed and executed.

Remarks
As you can see in the two screenshots, I get a flash of content where the font-size rule isn’t respected. I had this same issue with font-family actually, but dealt with it by putting it as an inline style on my <body> tag. Possibly this is a Flash of Unstyled Text (FOUT), but I’m honestly quite lost as to why these specific rules are being ignored on the first paint.
I state that the rules seem to be applied only after the main JS bundle is loaded/parsed/executed because of examining the request for app.js closely in the Chrome Network panel. Is this possible a webpack issue where I need to optimize the bundle further?
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 7
- Comments: 66 (32 by maintainers)
@probablyup - moving the
<StyleSheetManager>to a separate block aftergetDataFromTreeyielded the same effect, strangely.The only fix I can think of, whilst also rendering out a separate
<Html>React component and passingsheet.getStyleElement()to it, is to runrenderToStringon both parts, i.e.:… which seems to work fine.
My main point is that this is a material change vs. SC v3. In the previous version, it wasn’t necessary to call
renderToStringtwice. I could pass insheet.getStyleElement()to the component that got rendered out and it worked fine.Just curious whether this change was intentionally part of the new API? Maybe a performance thing?
@franky47 I think your issue is actually a next.js usage issue. Afaik the rendered elements in
_document.jsgenerate static markup, which might cause issues, since that’s not meant to be concurrency safe and it’ll also mess with our context-driven global styles.If you instead include the global style component in
_app.jsit should work correctly: https://github.com/zeit/next.js/#custom-appYeah, I understand most of the team has mentally (and possibly literally) checked out of v3 and are focusing on moving forward with the better designed API in v4. With a project like React-Static, however, we don’t have that luxury when hundreds of our users sites use styled-components v3.
Good luck on v4!