Styling
Next.js에서는 CSS를 사용하는 두 가지 기본 방법을 제공한다. Global CSS와 CSS Modules다.
Global CSS
전역 CSS는 애플리케이션 전체에 적용되는 스타일이다. Next.js에서는 pages/_app.tsx 파일에서만 Global CSS를 import할 수 있다.
왜 _app.tsx에서만 가능한가?
일반 컴포넌트나 페이지에서 Global CSS를 import하면 다른 페이지의 스타일과 충돌할 수 있다.
예를 들어 다음과 같은 상황을 생각해보자.
/* pages/home.css */
.button {
background: red;
}
/* pages/about.css */
.button {
background: blue;
}
// pages/index.tsx
import './home.css'; // ❌ 허용되지 않음
export default function Home() {
return <button className="button">홈</button>;
}
// pages/about.tsx
import './about.css'; // ❌ 허용되지 않음
export default function About() {
return <button className="button">소개</button>;
}
위 코드에서 / 페이지를 방문한 후 /about 페이지로 이동하면, home.css가 이미 로드된 상태에서 about.css가 추가로 로드된다. 두 CSS 파일 모두 .button 클래스를 정의하므로 스타일이 충돌한다.
Next.js는 클라이언트 사이드 네비게이션을 사용하므로, 페이지를 이동해도 이전 페이지의 CSS가 언로드되지 않는다. 따라서 모든 페이지의 CSS가 누적되면서 예측 불가능한 스타일 충돌이 발생한다.
사용법
_app.tsx는 모든 페이지에 공통으로 적용되는 컴포넌트이므로, 여기에서 Global CSS를 import하는 것은 안전하다.
// pages/_app.tsx
import '@/styles/globals.css'; // 허용됨
import type { AppProps } from 'next/app';
export default function App({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />;
}
/* styles/globals.css */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
a {
color: inherit;
text-decoration: none;
}
언제 사용하는가?
Global CSS는 다음과 같은 경우에 사용한다.
- CSS Reset 또는 Normalize
- 전역 폰트 설정
- 전역 색상 변수
- 모든 페이지에 공통으로 적용되는 기본 스타일
페이지나 컴포넌트별 스타일은 CSS Modules를 사용하는 것이 좋다.
CSS Modules
CSS Modules는 CSS 파일을 모듈로 import하여 로컬 스코프로 사용하는 방법이다. Next.js에 기본으로 내장되어 있어 별도 설정 없이 사용할 수 있다.
왜 필요한가?
일반 CSS는 전역 스코프를 사용하므로 클래스명이 충돌할 수 있다.
/* home.css */
.title {
color: red;
}
/* about.css */
.title {
color: blue;
}
두 파일 모두 .title 클래스를 정의하므로, 나중에 로드된 스타일이 이전 스타일을 덮어쓴다.
CSS Modules는 각 클래스명을 유니크한 이름으로 자동 변환하여 이 문제를 해결한다.
/* 원본 */
.title {
color: red;
}
/* 빌드 후 실제 클래스명 */
.Home_title__abc123 {
color: red;
}
사용법
CSS Modules를 사용하려면 파일명을 .module.css 형식으로 만든다.
/* components/Button.module.css */
.button {
padding: 12px 24px;
background: #0070f3;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.button:hover {
background: #0051cc;
}
컴포넌트에서 import하여 사용한다.
// components/Button.tsx
import styles from './Button.module.css';
export default function Button({ children }: { children: React.ReactNode }) {
return <button className={styles.button}>{children}</button>;
}
styles.button은 빌드 시 Button_button__abc123과 같은 유니크한 클래스명으로 변환된다.
여러 클래스 사용하기
여러 클래스를 함께 사용하려면 템플릿 리터럴이나 배열을 사용한다.
/* Card.module.css */
.card {
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
}
.featured {
border-color: #0070f3;
background: #f0f8ff;
}
// Card.tsx
import styles from './Card.module.css';
export default function Card({ featured }: { featured?: boolean }) {
return (
<div className={`${styles.card} ${featured ? styles.featured : ''}`}>
카드 내용
</div>
);
}
글로벌 클래스와 함께 사용
CSS Modules 내에서 글로벌 클래스를 선택해야 할 때는 :global 선택자를 사용한다.
/* Component.module.css */
.wrapper :global(.external-class) {
color: red;
}