みかづきブログ・カスタム

基本的にはちょちょいのほいです。

Next.js (Page Router)+ styled-components でページ表示時に一瞬スタイルが当たってない状態が表示されるのを防ぐ 💻

Next.js + styled-componentsでウェブサイトを作り始めてから、ずーっと気になっていました。
ページ表示時に一瞬スタイルが当たってない状態が表示のが。

が。

ついに、その解決方法を見つけました。

この、サーバサイドレンダリングを使えば解決します。

styled-components.com

更に、Next.jsでの例は公式がサンプルを用意してくれています。

github.com


_document.jsx

import Document from 'next/document';
import { ServerStyleSheet } from 'styled-components';

export default class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      ctx.renderPage = () => {
        return originalRenderPage({
          enhanceApp: (App) => (props) =>
            sheet.collectStyles(<App {...props} />)
        });
      };

      const initialProps = await Document.getInitialProps(ctx);

      return {
        ...initialProps,
        styles: (
          <>
            { initialProps.styles }
            { sheet.getStyleElement() }
          </>
        ),
      }
    } finally {
      sheet.seal();
    }
  }
}

こちらの、_document.jsxをpage直下に設置すればOKです。

TypeScriptで書くと、

_document.tsx

import Document, { DocumentContext } from 'next/document';
import { ServerStyleSheet } from 'styled-components';

export default class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      ctx.renderPage = () => {
        return originalRenderPage({
          enhanceApp: (App) =>
            function MyDocument(props) {
              return sheet.collectStyles(<App {...props} />);
            }
        });
      };

      const initialProps = await Document.getInitialProps(ctx);

      return {
        ...initialProps,
        styles: (
          <>
            { initialProps.styles }
            { sheet.getStyleElement() }
          </>
        )
      };
    } finally {
      sheet.seal();
    }
  }
}

という感じです。