Next.js에 Styled-components 정의하기

jonyChoiGenius·2023년 1월 15일
0

yarn add styled-components
yarn add @types/styled-components -D로 설치한다. @types/styled-components를 설치해야 타입스크립트에서 스타일드 컴포넌츠를 자동완성 할 수 있다.

스타일드 컴포넌트를 ssr에 적용하면 새로고침할 때에 스타일이 적용되지 않는 문제가 발생할 수 있다. _document.tsx를 확장하여 문제를 해결할 수 있다.

pages/_document.tsx는 아래와 같은 형태를 가진다.

import { Html, Head, Main, NextScript } from "next/document";

export default function Document() {
  return (
    <Html lang="en">
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}

next js 공식문서 예제블로그 글를 참조하여 아래와 같이 수정한다.

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 = () =>
        originalRenderPage({
          enhanceApp: (App) => (props) =>
            sheet.collectStyles(<App {...props} />),
        });

      const initialProps = await Document.getInitialProps(ctx);
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        ),
      };
    } finally {
      sheet.seal();
    }
  }
}

yarn add babel-plugin-styled-components를 통해 babel 플러그인을 설치해주자.

루트 폴더에 .babelrc를 아래와 같이 추가해준다

{
  "presets": ["next/babel"],
  "plugins": [
    [
      "babel-plugin-styled-components",
      {
        "ssr": true,
        "displayName": true //개발 모드일 때에 stled-components 클래스명 확인할 수 있도록
      }
    ]
  ]
}

글로벌 스타일 적용하기

components폴더에 GlobalStyle.ts 파일을 만들었다.

그리고 아래와 같이 스타일드 컴포넌트의 GlobalStyle을 만들어서 적용하였다.

import { createGlobalStyle } from "styled-components";

const GlobalStyle = createGlobalStyle`
/* http://meyerweb.com/eric/tools/css/reset/
  v2.0 | 20110126
  License: none (public domain)
*/

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
  display: block;
}
body {
  line-height: 1;
}
ol, ul {
  list-style: none;
}
blockquote, q {
  quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
  content: '';
  content: none;
}
table {
  border-collapse: collapse;
  border-spacing: 0;
}
  `;

export default GlobalStyle;

CSS스타일은 에릭 메이어의 reset css 2.0 버전이다.

pages/_app.tsx를 만들어 아래와 같이 글로벌 스타일을 정의한다.

CRA로 했을 때의 코드

import '@/styles/globals.css'
import type { AppProps } from 'next/app'

export default function App({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />
}

직접 정의한 코드 (자동완성이 되지 않아 vscode 확장에서 npm Intellisense를 설치하였음.)

import App, { AppProps } from "next/app";
import GlobalStyle from "../styles/GlobalStyle";

const app = ({ Component, pageProps }: AppProps) => {
  return (
    <>
      <GlobalStyle />
      <Component {...pageProps} />
    </>
  );
};

웹 폰트 적용하기

나눔 스퀘어를 적용해보도록 하자.

먼저 pages/_document.tsx에서 render()를 추가해주어야 한다.

import Document, { Html, Main, NextScript } from "next/document";
import Head from "next/head";
import { ServerStyleSheet } from "styled-components";

export default class MyDocument extends Document {...;
    } finally {
      sheet.seal();
    }
  }

  render() {
    return (
      <Html>
        <Head>
          <link
            rel="stylesheet"
            type="text/css"
            href="https://cdn.jsdelivr.net/gh/moonspam/NanumSquare@2.0/nanumsquare.css"
          />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

이후 GlobalFontFamily.ts라는 새로운 스타일을 만들자.

import { css } from "styled-components";

const GlobalFontFamily = css`
  body {
    font-family: "NanumSquare", sans-serif;
  }
  .font-weight-400 {
    font-weight: 400;
  }
  .font-weight-700 {
    font-weight: 700;
  }
  .font-weight-800 {
    font-weight: 800;
  }
  .font-weight-300 {
    font-weight: 300;
  }
`;

export default GlobalFontFamily;

기존에 있던 css reset 부분도 GlobalResetStyle이라는 새로운 ts파일로 분리하자.

import { css } from "styled-components";

const GlobalResetStyle = css`
  /* http://meyerweb.com/eric/tools/css/reset/
  v2.0 | 20110126
  License: none (public domain)
*/

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
  display: block;
}
body {
  line-height: 1;
}
ol, ul {
  list-style: none;
}
blockquote, q {
  quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
  content: '';
  content: none;
}
table {
  border-collapse: collapse;
  border-spacing: 0;
}
`;

export default GlobalResetStyle;

이후 아래와 같이 resetStyle를 먼저 넣어주고, fontFamily를 나중에 넣어주면 된다.

import { createGlobalStyle } from "styled-components";
import GlobalFontFamily from "./GlobalFontFamily";
import GlobalResetStyle from "./GlobalResetStyle";

const GlobalStyle = createGlobalStyle`
${GlobalResetStyle}
${GlobalFontFamily}
  `;

export default GlobalStyle;
``


profile
천재가 되어버린 박제를 아시오?

0개의 댓글