처음 만난 Next.js 문서


11.1

CSS Modules와 Global Styles

11.1.1 CSS Modules

Next.js는 기본적으로 .module.css 확장자를 사용하는 파일을 통해 CSS Modules를 지원합니다. 이러한 CSS Modules는 고유한 클래스 이름을 자동으로 생성함으로써 CSS를 로컬 범위로 제한합니다. 이를 통해 다른 파일에서 동일한 클래스 이름을 사용하더라도 충돌에 대해 걱정할 필요가 없습니다. 이런 특징으로 인해 CSS Modules는 컴포넌트 수준의 CSS를 작성하는 이상적인 방법이라고 할 수 있습니다. 그리고 Production 빌드 시에는 모든 CSS Modules 파일이 최소화(Minification)되고 코드 분할(Code Splitting)된 여러 개의 연결된 .css 파일로 변환됩니다. 결과적으로 애플리케이션이 렌더링되는 데 필요한 최소한의 CSS만 로드되도록 보장합니다.

아래 예시 코드는 CSS Modules를 사용한 예시 코드입니다. 이 코드와 같이 app 디렉토리에 있는 어떤 파일에서든지 CSS Modules를 import할 수 있습니다. 참고로 CSS Modules는 .module.css.module.sass 확장자로 된 파일에 한해서만 지원됩니다.

// app/blog/layout.tsx

import styles from './styles.module.css';

interface BlogLayoutProps {
    children: React.ReactNode;
}

function BlogLayout(props: BlogLayoutProps) {
    return <section className={styles.blog}>{props.children}</section>;
}

export default BlogLayout;
/* app/blog/styles.module.css */

.blog {
    padding: 16px 24px;
}

11.1.2 Global Styles

Global Styles는 이름 그대로 애플리케이션 전체에 적용되는 스타일입니다. App Router에서 Global Styles은 app 폴더 안에 있는 레이아웃, 페이지, 컴포넌트에서 import해서 사용할 수 있습니다. 기존에 Pages Router에서는 _app.js 파일 내에서만 Global Styles를 적용할 수 있었던 것과는 차이가 있습니다.

아래 예시 코드는 app 폴더 내에 global.css 라는 CSS 파일을 작성한 이후에, RootLayout에서 해당 CSS 파일을 import해서 Global Styles를 적용하는 예시입니다.

/* app/global.css */

body {
    max-width: 960px;
    margin: 0 auto;
    padding: 16px 16px 56px;
}
// app/layout.tsx

import './global.css';  // 애플리케이션의 모든 route에 대해 적용됨

interface RootLayoutProps {
    children: React.ReactNode;
}

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

    return (
        <html lang="en">
            <body>{children}</body>
        </html>
    );
}

export default RootLayout;

11.1.3 External Stylesheets

External Stylesheets는 외부 패키지에서 제공하는 Stylesheets를 의미하며, 아래 예시 코드와 같이 app 폴더 어디에서나 가져와서 사용할 수 있습니다.

// app/layout.tsx

import 'bootstrap/dist/css/bootstrap.css';

interface RootLayoutProps {
    children: React.ReactNode;
}

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

    return (
        <html lang="en">
            <body className='container'>{children}</body>
        </html>
    );
}

export default RootLayout;

참고로 External Stylesheets는 <link rel="stylesheet" /> 형태로 사용할 수 없으며, npm 패키지로부터 직접 import 하거나 파일을 다운로드하여 프로젝트 폴더 내에 위치시켜야 합니다.

11.1.4 Ordering and Merging

Next.js는 Production 빌드 시 Stylesheets를 자동으로 chunking(merging)하여 CSS를 최적화합니다. 이 때 CSS의 순서는 애플리케이션 코드에 Stylesheets를 가져오는 순서에 따라 결정됩니다.

예를 들면, 아래 예시 코드와 같이 <BaseButton><Page>에서 먼저 import되었기 때문에 base-button.module.csspage.module.css보다 이전 순서에 위치하게 됩니다.

// app/base-button.tsx

import styles from './base-button.module.css';

export function BaseButton() {
    return <button className={styles.primary} />;
}
// app/page.tsx

import { BaseButton } from './base-button';
import styles from './page.module.css';

export function Page() {
    return <BaseButton className={styles.primary} />;
}

그리고 CSS가 적용되는 순서를 예측 가능하도록 하기 위해서는 아래와 같은 권장방법들을 사용하는 것이 좋습니다.

  • CSS 파일은 단일 JavaScript/TypeScript 파일에서만 가져오기
    • 글로벌 클래스 이름을 사용하는 경우, 같은 파일에서 Global Styles를 적용되기 원하는 순서대로 import 하기
  • Global Styles보다 CSS Modules를 사용하기
    • CSS Modules에 일관된 네이밍 규칙 사용하기 (예: <name>.tsx 대신 <name>.module.css 사용)
  • 공유 스타일은 별도의 공유 컴포넌트로 추출하기
  • Tailwind CSS를 사용하는 경우, Stylesheets를 파일의 최상단에서 import하고 가능하면 Root Layout에서 가져오기

NOTE. 유의사항
CSS 순서는 개발 모드에서 다르게 동작하므로, Production 빌드에서 최종 CSS 순서를 확인하려면 항상 Preview 배포를 확인하는 것이 좋음


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

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

On this page