처음 만난 Next.js 문서


11.3

CSS-in-JS

CSS-in-JS는 JavaScript 코드 내에서 CSS 스타일을 작성하고 관리할 수 있게 해주는 방법입니다. CSS-in-JS 방식을 사용하면 스타일을 컴포넌트와 함께 결합하여 동적인 스타일 적용과 스코프 범위를 컴포넌트 단위로 제한할 수 있습니다.

Next.js에서 CSS-in-JS를 사용하기 위해서는 아래와 같은 설정이 필요합니다.

  1. 렌더링에서 모든 CSS 규칙을 수집하는 style registry
  2. useServerInsertedHTML()을 사용하여 규칙을 사용하는 모든 콘텐츠 앞에 규칙을 삽입
  3. 초기 서버 사이드 렌더링 동안 style registry로 앱을 감싸는 클라이언트 컴포넌트

11.3.1 styled-jsx

styled-jsx는 Next.js에 기본적으로 포함된 CSS-in-JS 라이브러리로, React 컴포넌트에 CSS 스타일을 컴포넌트 단위로 작성하고 스코프를 제한할 수 있도록 해줍니다. styled-jsx를 사용하면 각 컴포넌트에 스타일이 캡슐화되어 다른 컴포넌트와의 스타일 충돌을 방지할 수 있습니다. 또한 간단한 문법으로 CSS를 작성할 수 있으며, Next.js의 SSR(서버 사이드 렌더링)과도 잘 통합됩니다.

styled-jsx를 적용하기 위해서는 먼저 아래 코드와 같이 새로운 style registry를 생성해야 합니다.

// app/registry.tsx

'use client';

import React, { useState } from 'react';
import { useServerInsertedHTML } from 'next/navigation';
import { StyleRegistry, createStyleRegistry } from 'styled-jsx';

function StyledJsxRegistry({ children }: { children: React.ReactNode }) {
    // Only create stylesheet once with lazy initial state
    const [jsxStyleRegistry] = useState(() => createStyleRegistry());

    useServerInsertedHTML(() => {
        const styles = jsxStyleRegistry.styles();
        jsxStyleRegistry.flush();
        return <>{styles}</>;
    });

    return (
        <StyleRegistry registry={jsxStyleRegistry}>{children}</StyleRegistry>
    );
}

export default StyledJsxRegistry;

그리고 아래 코드와 같이 생성한 style registry로 RootLayout의 children을 감싸주면 됩니다.

// app/layout.tsx

import StyledJsxRegistry from './registry';

interface RootLayoutProps {
    children: React.ReactNode;
}

function RootLayout(props: RootLayoutProps) {
    const { children } = props;

    return (
        <html>
            <body>
                <StyledJsxRegistry>{children}</StyledJsxRegistry>
            </body>
        </html>
    );
}

export default RootLayout;

11.3.2 styled-components

styled-components는 가장 대표적인 CSS-in-JS 라이브러리 중 하나입니다. Next.js에서 styled-components를 사용하기 위해서는, 먼저 아래와 같이 next.config.js 파일에서 styled-components를 활성화해야 합니다.

// next.config.js

module.exports = {
    compiler: {
        styledComponents: true,
    },
};

그런 다음 아래와 같이 styled-components API를 사용하여 렌더링 중에 생성된 모든 CSS 스타일 규칙을 수집하는 전역 레지스트리 컴포넌트를 만듭니다. 이 전역 레지스트리 컴포넌트는 useState() 훅의 초기값으로 함수를 넘기는 lazy initial state라는 방법을 사용하여 stylesheet가 한 번만 생성되도록 합니다. 그리고 useServerInsertedHTML() 훅을 사용하여 레지스트리에 수집된 스타일을 Root Layout의 <head> HTML 태그에 삽입해줍니다.

// lib/registry.tsx

'use client';

import React, { useState } from 'react';
import { useServerInsertedHTML } from 'next/navigation';
import { ServerStyleSheet, StyleSheetManager } from 'styled-components';

function StyledComponentsRegistry({ children }: { children: React.ReactNode }) {
    // lazy initial state를 사용하여 stylesheet를 한 번만 생성함
    // x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
    const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet());

    useServerInsertedHTML(() => {
        const styles = styledComponentsStyleSheet.getStyleElement();
        styledComponentsStyleSheet.instance.clearTag();
        return <>{styles}</>;
    });

    if (typeof window !== 'undefined') return <>{children}</>;

    return (
        <StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
            {children}
        </StyleSheetManager>
    );
}

export default StyledComponentsRegistry;

이후 아래 코드와 같이 Root Layout의 childrenStyledComponentsRegistry 컴포넌트로 감싸주면 됩니다.

// app/layout.tsx

import StyledComponentsRegistry from './lib/registry';

interface RootLayoutProps {
    children: React.ReactNode;
}

function RootLayout(props: RootLayoutProps) {
    const { children } = props;

    return (
        <html>
            <body>
                <StyledComponentsRegistry>
                    {children}
                </StyledComponentsRegistry>
            </body>
        </html>
    );
}

export default RootLayout;

마지막 업데이트: 2025년 10월 24일 02시 45분

이 문서의 저작권은 이인제(소플)에 있습니다. 무단 전재와 무단 복제를 금합니다.

On this page

  • 11.3 CSS-in-JS

  • 11.3.1 styled-jsx

  • 11.3.2 styled-components