스타일링: CSS Modules와 Tailwind를 디자인 토큰으로 이해하기
오늘의 목표: 스타일이 어디에서 관리되는지 보기
지난 장에서는 포트폴리오 첫 화면을 만들었습니다.
구조는 이미 있습니다.
main.page
├─ Hero Section
├─ About Section
└─ Projects Section
├─ Project Card
└─ Project Card이번 장에서는 이 구조에 입혀진 스타일을 더 체계적으로 이해합니다.
디자이너에게 스타일링은 낯선 일이 아닙니다. Figma에서도 매일 하고 있습니다.
색상 선택
글꼴 지정
간격 맞추기
오토레이아웃 설정
반응형 프레임 확인
컴포넌트 variant 만들기웹 코드에서도 같은 일을 합니다. 다만 도구의 이름이 바뀝니다.
Figma Color Style → CSS color 또는 Tailwind 색상 클래스
Figma Text Style → font-size, line-height, font-weight
Figma Spacing Token → padding, margin, gap
Figma Auto Layout → flex, grid
Figma Constraints → width, max-width, media query
Figma Component Variant → class 조합 또는 조건부 스타일이번 장의 핵심은 문법을 많이 외우는 것이 아닙니다.
디자인 결정이 코드에서 어디에 저장되고, 어떻게 반복되고, 언제 깨지는지 보는 눈을 갖는 것입니다.
Next.js 공식 학습 코스에서도 Next.js 앱을 스타일링하는 대표적인 방식으로 전역 CSS, Tailwind CSS, CSS Modules를 소개합니다. Tailwind와 CSS Modules는 둘 중 하나만 써야 하는 방식이 아니라, 프로젝트에 따라 함께 사용할 수도 있습니다.1

먼저 구분하기: 전역 스타일과 로컬 스타일
지난 장에서 우리는 app/globals.css에 스타일을 넣었습니다.
이름 그대로 globals.css는 전역 스타일입니다.
전역 스타일은 사이트 전체에 깔리는 기본 규칙입니다.
globals.css
├─ body 배경색
├─ 기본 글꼴
├─ 전체 box-sizing
├─ h1, h2, p의 기본 여백
└─ 사이트 전체에서 공유하는 기본 스타일Figma로 비유하면 팀 전체가 공유하는 스타일 가이드에 가깝습니다.
Figma Team Library
├─ Color Styles
├─ Text Styles
└─ Effect Styles전역 스타일은 편리합니다. 하지만 모든 곳에 영향을 줍니다.
예를 들어 h1 스타일을 전역으로 바꾸면 사이트 안의 모든 h1이 바뀔 수 있습니다.
h1 {
font-size: 48px;
}이것은 Figma에서 모든 Heading/Large 텍스트 스타일을 수정하는 것과 비슷합니다. 의도했다면 좋지만, 특정 화면만 바꾸고 싶었는데 전체가 바뀌면 문제가 됩니다.
그래서 스타일은 보통 두 층으로 나눠서 생각합니다.
전역 스타일
→ 사이트 전체의 기본값과 디자인 토큰
로컬 스타일
→ 특정 페이지나 특정 컴포넌트의 모양이번 장에서 배울 CSS Modules는 이 두 번째 영역, 즉 로컬 스타일을 다루는 방법입니다.
CSS Modules: 특정 컴포넌트 안에서만 작동하는 스타일
CSS Modules는 쉽게 말해 이 컴포넌트에만 적용되는 CSS 파일입니다.
보통 CSS는 클래스 이름이 같으면 서로 영향을 줄 수 있습니다.
.card {
padding: 24px;
}다른 파일에서도 .card라는 이름을 쓰면 충돌할 수 있습니다.
ProjectCard의 .card
ArticleCard의 .card
PricingCard의 .card사람이 보기에는 모두 card입니다. 하지만 각각 원하는 모양이 다를 수 있습니다.
CSS Modules는 이 문제를 줄여 줍니다. .module.css 파일에 쓴 클래스 이름을 Next.js가 내부적으로 고유한 이름으로 바꿔 주기 때문입니다. 공식 학습 코스에서도 CSS Modules는 컴포넌트 단위로 CSS 범위를 제한하고, 자동으로 고유한 클래스 이름을 만들어 스타일 충돌을 막는 방식이라고 설명합니다.1
디자이너 관점에서는 이렇게 이해하면 됩니다.
일반 CSS 클래스
→ 팀 파일 전체에 같은 이름으로 보이는 레이어 이름
CSS Modules 클래스
→ 특정 컴포넌트 안에서만 의미가 있는 레이어 이름Figma 컴포넌트 안에 Title, Description, Thumbnail이라는 레이어가 있을 수 있습니다. 다른 컴포넌트 안에도 똑같은 이름의 Title 레이어가 있을 수 있습니다.
하지만 그것이 곧바로 충돌하지는 않습니다. 각 컴포넌트 안에서만 해석되기 때문입니다.
CSS Modules도 비슷합니다.
ProjectCard.module.css의 .title
Hero.module.css의 .title
둘 다 title이지만 서로 다른 영역의 title실습 1: 포트폴리오 페이지를 CSS Modules로 정리하기
지난 장에서는 app/globals.css에 많은 스타일을 넣었습니다.
이번에는 페이지 전용 스타일을 app/page.module.css로 옮겨 보겠습니다.
폴더 구조는 이렇게 됩니다.
app
├─ page.tsx
├─ page.module.css
├─ layout.tsx
└─ globals.cssglobals.css에는 전체 기본값만 남깁니다.
* {
box-sizing: border-box;
}
body {
margin: 0;
background: #f7f3ee;
color: #1f1f1f;
font-family: Arial, sans-serif;
}
h1,
h2,
h3,
p {
margin-top: 0;
}그리고 app/page.module.css 파일을 새로 만듭니다.
.page {
width: min(1080px, calc(100% - 40px));
margin: 0 auto;
padding: 64px 0;
}
.heroSection {
display: grid;
grid-template-columns: 1fr auto;
gap: 40px;
align-items: center;
padding: 56px;
border-radius: 32px;
background: #ffffff;
}
.eyebrow {
margin: 0 0 12px;
color: #7a5cff;
font-size: 14px;
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.heroTitle {
max-width: 720px;
font-size: 48px;
line-height: 1.08;
letter-spacing: -0.04em;
}
.heroText {
max-width: 640px;
color: #4b4b4b;
font-size: 18px;
line-height: 1.7;
}
.profileImage {
border-radius: 50%;
object-fit: cover;
}
.section {
margin-top: 32px;
padding: 48px;
border-radius: 32px;
background: #ffffff;
}
.sectionTitle {
max-width: 760px;
font-size: 32px;
line-height: 1.2;
letter-spacing: -0.03em;
}
.sectionText {
color: #4b4b4b;
font-size: 18px;
line-height: 1.7;
}
.projectGrid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 24px;
margin-top: 24px;
}
.projectCard {
overflow: hidden;
border: 1px solid #e7e0d8;
border-radius: 24px;
background: #fffdf9;
}
.projectImage {
width: 100%;
height: auto;
display: block;
}
.projectContent {
padding: 24px;
}
.projectTitle {
margin-bottom: 8px;
font-size: 22px;
}
.projectDescription {
margin-bottom: 0;
color: #4b4b4b;
font-size: 16px;
line-height: 1.6;
}
@media (max-width: 760px) {
.heroSection {
grid-template-columns: 1fr;
padding: 32px;
}
.heroTitle {
font-size: 36px;
}
.section {
padding: 32px;
}
.sectionTitle {
font-size: 26px;
}
.projectGrid {
grid-template-columns: 1fr;
}
}이제 app/page.tsx에서 이 CSS 파일을 불러옵니다.
import Image from "next/image";
import styles from "./page.module.css";그리고 기존의 문자열 클래스 이름을 styles.이름 형태로 바꿉니다.
<main className={styles.page}>
<section className={styles.heroSection}>
<div>
<p className={styles.eyebrow}>Product Designer Portfolio</p>
<h1 className={styles.heroTitle}>
사용자의 문제를 화면의 구조로 바꾸는 디자이너, 민지입니다.
</h1>
<p className={styles.heroText}>
저는 리서치에서 발견한 문제를 정보 구조, 사용자 흐름, 인터페이스로 연결하는 일을 합니다.
</p>
</div>
<Image
src="/profile.jpg"
alt="프로덕트 디자이너 민지의 프로필 사진"
width={160}
height={160}
className={styles.profileImage}
/>
</section>
</main>처음 보면 className="page"보다 className={styles.page}가 더 복잡해 보입니다.
하지만 의미는 분명합니다.
className="page"
→ 전역에서 page라는 이름을 찾는다
className={styles.page}
→ 이 파일이 import한 CSS Module 안에서 page를 찾는다Figma로 바꾸면 이런 차이입니다.
전역 className
→ 팀 전체 라이브러리에서 같은 이름의 스타일 찾기
CSS Modules
→ 이 컴포넌트 옆에 붙어 있는 전용 스타일 찾기CSS Modules는 이런 경우에 특히 좋습니다.
- 특정 컴포넌트의 세부 스타일이 많을 때
- JSX 안에 클래스 이름이 너무 길게 들어가는 것이 싫을 때
- 전통적인 CSS 문법으로 차분하게 스타일을 관리하고 싶을 때
- 스타일 충돌을 줄이고 싶을 때디자인 토큰: 숫자와 색상에 이름을 붙이는 일
지금 CSS에는 숫자와 색상이 직접 들어 있습니다.
padding: 56px;
border-radius: 32px;
background: #ffffff;
color: #7a5cff;작은 프로젝트에서는 괜찮습니다. 하지만 화면이 많아지면 문제가 생깁니다.
어떤 화면은 24px
어떤 화면은 25px
어떤 화면은 #7a5cff
어떤 화면은 #7658ff눈으로 보면 거의 비슷하지만, 코드에서는 모두 다른 값입니다.
디자인 시스템에서는 이런 문제를 줄이기 위해 토큰을 씁니다.
color.brand.primary = #7a5cff
color.surface.default = #ffffff
space.6 = 24px
radius.lg = 24px코드에서도 비슷한 방식으로 CSS 변수를 만들 수 있습니다.
app/globals.css에 토큰처럼 사용할 값을 정의해 봅니다.
:root {
--color-bg: #f7f3ee;
--color-surface: #ffffff;
--color-surface-soft: #fffdf9;
--color-text: #1f1f1f;
--color-text-muted: #4b4b4b;
--color-brand: #7a5cff;
--color-border: #e7e0d8;
--space-3: 12px;
--space-4: 16px;
--space-6: 24px;
--space-8: 32px;
--space-10: 40px;
--space-12: 48px;
--space-14: 56px;
--space-16: 64px;
--radius-lg: 24px;
--radius-xl: 32px;
}
body {
margin: 0;
background: var(--color-bg);
color: var(--color-text);
font-family: Arial, sans-serif;
}이제 page.module.css에서는 직접 색상 값을 쓰는 대신 토큰을 부릅니다.
.heroSection {
display: grid;
grid-template-columns: 1fr auto;
gap: var(--space-10);
align-items: center;
padding: var(--space-14);
border-radius: var(--radius-xl);
background: var(--color-surface);
}
.eyebrow {
margin: 0 0 var(--space-3);
color: var(--color-brand);
font-size: 14px;
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
}이렇게 하면 디자인 결정이 한 곳에 모입니다.
브랜드 컬러를 바꿔야 한다
→ --color-brand만 수정
카드 radius를 바꿔야 한다
→ --radius-lg 또는 --radius-xl 수정
간격 체계를 조정해야 한다
→ --space-* 값 확인디자이너에게 중요한 지점은 여기입니다.
개별 화면의 픽셀값을 하나씩 맞추는 것보다, 팀이 공유하는 토큰 이름과 규칙을 맞추는 것이 더 중요합니다.
Figma의 변수나 스타일과 코드의 토큰 이름이 연결되면 핸드오프가 훨씬 선명해집니다.
Figma variable: color/brand/primary
Code token: --color-brand
Figma spacing: spacing/6
Code token: --space-6이름이 같거나 대응표가 있으면 디자이너와 개발자가 같은 언어로 이야기할 수 있습니다.
Tailwind CSS: 토큰을 짧은 조각으로 조합하는 방식
이번에는 Tailwind CSS를 보겠습니다.
Tailwind는 CSS 파일에 긴 규칙을 따로 쓰기보다, JSX 안에 작은 유틸리티 클래스를 조합해서 스타일을 만드는 방식입니다. 공식 학습 코스에서는 Tailwind를 React 코드 안에 유틸리티 클래스를 직접 붙여 빠르게 스타일링할 수 있게 해 주는 CSS 프레임워크로 설명합니다.1
예를 들어 CSS Modules에서는 이렇게 씁니다.
.projectCard {
overflow: hidden;
border: 1px solid #e7e0d8;
border-radius: 24px;
background: #fffdf9;
}Tailwind 방식으로는 JSX 안에 이렇게 씁니다.
<article className="overflow-hidden rounded-3xl border border-stone-200 bg-stone-50">
...
</article>처음 보면 HTML 안이 지저분해 보일 수 있습니다. 하지만 관점을 바꾸면 다르게 보입니다.
Tailwind 클래스는 하나하나가 작은 디자인 토큰 호출입니다.
rounded-3xl → 큰 radius
border → 1px border
border-stone-200 → 연한 회색 border
bg-stone-50 → 아주 밝은 배경색
p-6 → padding scale 6
gap-6 → gap scale 6
text-sm → 작은 글자 크기
font-bold → 굵은 글자Figma로 비유하면, 오른쪽 패널에서 속성을 하나씩 고르는 대신 레이어 이름 옆에 속성 칩을 붙이는 느낌입니다.
Project Card
[overflow-hidden] [rounded-3xl] [border] [bg-stone-50] [p-6]Tailwind의 장점은 빠른 조합입니다.
카드에 padding 추가 → p-6
간격 추가 → gap-6
모바일에서 1열, 데스크톱에서 2열 → grid-cols-1 md:grid-cols-2
글자색 변경 → text-stone-600단점도 있습니다.
클래스가 길어지면 JSX가 복잡해 보입니다. 그리고 팀의 디자인 토큰과 Tailwind의 기본 scale이 맞지 않으면, 디자이너가 의도한 값과 개발자가 고른 값이 어긋날 수 있습니다.
그래서 Tailwind를 쓸 때도 중요한 질문은 같습니다.
우리 팀의 색상, 간격, radius, 타이포그래피 토큰이
Tailwind 설정과 어떻게 연결되어 있는가?Hero, ProjectCard, Button을 두 방식으로 바라보기
같은 화면도 CSS Modules 방식과 Tailwind 방식으로 표현할 수 있습니다.
어느 하나가 무조건 정답은 아닙니다. 팀의 취향, 프로젝트 규모, 디자인 시스템의 성숙도에 따라 달라집니다.
Hero 섹션
CSS Modules 방식은 스타일 이름을 먼저 정합니다.
<section className={styles.heroSection}>
<div>
<p className={styles.eyebrow}>Product Designer Portfolio</p>
<h1 className={styles.heroTitle}>사용자의 문제를 화면의 구조로 바꾸는 디자이너</h1>
</div>
</section>이 방식은 읽을 때 구조가 깔끔합니다.
heroSection
eyebrow
heroTitleFigma 레이어 이름처럼 보입니다. 대신 실제 padding, gap, background 값을 보려면 CSS 파일을 열어야 합니다.
Tailwind 방식은 값이 JSX 안에 바로 보입니다.
<section className="grid items-center gap-10 rounded-[32px] bg-white p-14 md:grid-cols-[1fr_auto]">
<div>
<p className="mb-3 text-sm font-bold uppercase tracking-wide text-violet-500">
Product Designer Portfolio
</p>
<h1 className="max-w-3xl text-5xl font-bold leading-tight tracking-tight">
사용자의 문제를 화면의 구조로 바꾸는 디자이너
</h1>
</div>
</section>이 방식은 속성이 바로 보입니다. 대신 클래스가 길어지면 처음 읽는 사람에게 부담이 됩니다.
ProjectCard
프로젝트 카드는 반복되는 컴포넌트입니다.
Figma에서는 Project Card 컴포넌트를 만들고, 각 인스턴스의 제목과 이미지를 바꿉니다.
코드에서도 같은 감각으로 볼 수 있습니다.
CSS Modules 방식:
<article className={styles.projectCard}>
<Image
src={project.image}
alt={`${project.title} 썸네일`}
width={640}
height={400}
className={styles.projectImage}
/>
<div className={styles.projectContent}>
<h3 className={styles.projectTitle}>{project.title}</h3>
<p className={styles.projectDescription}>{project.description}</p>
</div>
</article>Tailwind 방식:
<article className="overflow-hidden rounded-3xl border border-stone-200 bg-stone-50">
<Image
src={project.image}
alt={`${project.title} 썸네일`}
width={640}
height={400}
className="block h-auto w-full"
/>
<div className="p-6">
<h3 className="mb-2 text-xl font-bold">{project.title}</h3>
<p className="mb-0 text-base leading-relaxed text-stone-600">
{project.description}
</p>
</div>
</article>디자이너가 읽기에는 CSS Modules가 더 컴포넌트 이름 중심입니다.
projectCard
projectImage
projectContent
projectTitleTailwind는 속성 중심입니다.
overflow-hidden
rounded-3xl
border
p-6
text-base두 방식은 보는 초점이 다릅니다.
CSS Modules
→ 이 요소가 어떤 역할인가?
Tailwind
→ 이 요소에 어떤 시각 속성이 붙어 있는가?Button과 variant
포트폴리오에는 연락 버튼이 필요합니다.
Hero 섹션 아래에 버튼을 하나 추가한다고 생각해 봅시다.
<a href="mailto:[email protected]" className={styles.button}>
연락하기
</a>CSS Modules에서는 기본 버튼과 variant를 나눌 수 있습니다.
.button {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 48px;
padding: 0 var(--space-6);
border-radius: 999px;
font-weight: 700;
text-decoration: none;
}
.primaryButton {
background: var(--color-brand);
color: #ffffff;
}
.secondaryButton {
border: 1px solid var(--color-border);
background: var(--color-surface);
color: var(--color-text);
}사용할 때는 클래스를 조합합니다.
<a
href="mailto:[email protected]"
className={`${styles.button} ${styles.primaryButton}`}
>
연락하기
</a>Figma로 보면 이 구조입니다.
Button Component
├─ base style: 높이, radius, padding, 정렬
└─ variant
├─ primary: 보라색 배경
└─ secondary: 흰 배경 + borderTailwind 방식에서는 variant를 클래스 조합으로 표현합니다.
<a
href="mailto:[email protected]"
className="inline-flex min-h-12 items-center justify-center rounded-full bg-violet-500 px-6 font-bold text-white no-underline"
>
연락하기
</a>버튼이 많아지면 매번 긴 클래스를 반복하기보다 Button 컴포넌트로 분리합니다.
Button 컴포넌트
- variant: primary | secondary
- size: small | medium | large이때 개발자는 조건에 따라 클래스를 바꿉니다. 공식 학습 코스에서는 조건에 따라 클래스 이름을 쉽게 토글할 때 clsx 같은 도구를 사용할 수 있다고 소개합니다.1
디자이너는 여기서 중요한 질문을 할 수 있습니다.
Figma의 Button variant가 코드에서도 variant로 구현되어 있나요?
primary, secondary, disabled 상태 이름이 서로 같나요?이 질문은 디자인 시스템과 코드 컴포넌트를 연결하는 질문입니다.
반응형 레이아웃: Auto Layout과 Constraints로 이해하기
반응형은 화면 크기에 따라 레이아웃이 바뀌는 규칙입니다.
디자이너에게는 이미 익숙한 개념입니다.
Figma에서 모바일, 태블릿, 데스크톱 프레임을 만들 때 이런 고민을 합니다.
카드가 2열로 있을 것인가, 1열로 쌓일 것인가?
이미지는 오른쪽에 둘 것인가, 위로 올릴 것인가?
섹션 padding은 유지할 것인가, 줄일 것인가?
텍스트 크기는 언제 줄일 것인가?CSS에서도 같은 결정을 합니다.
지난 장에서 쓴 코드를 다시 보겠습니다.
.projectGrid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 24px;
}
@media (max-width: 760px) {
.projectGrid {
grid-template-columns: 1fr;
}
}이 뜻은 간단합니다.
기본 상태
→ 프로젝트 카드를 2열로 보여 준다
화면 너비가 760px 이하일 때
→ 프로젝트 카드를 1열로 쌓는다Figma로 비유하면 이렇습니다.
Desktop Frame
Project Grid: Horizontal, 2 columns
Mobile Frame
Project Grid: Vertical, 1 column@media (max-width: 760px)는 일종의 분기점입니다. 보통 breakpoint라고 부릅니다.
breakpoint
→ 레이아웃 규칙이 바뀌는 화면 너비 기준점Figma에서 데스크톱 프레임과 모바일 프레임을 따로 만들어 비교하듯, CSS에서는 breakpoint를 기준으로 규칙을 바꿉니다.
Hero 섹션도 마찬가지입니다.
.heroSection {
display: grid;
grid-template-columns: 1fr auto;
}
@media (max-width: 760px) {
.heroSection {
grid-template-columns: 1fr;
}
}해석하면 이렇게 됩니다.
데스크톱
소개 문구 | 프로필 이미지
모바일
소개 문구
프로필 이미지Tailwind에서는 같은 규칙을 클래스 이름으로 표현합니다.
<section className="grid grid-cols-1 gap-10 rounded-[32px] bg-white p-8 md:grid-cols-[1fr_auto] md:p-14">
...
</section>여기서 md:는 특정 화면 크기 이상에서 적용되는 조건입니다.
grid-cols-1
→ 기본은 1열
md:grid-cols-[1fr_auto]
→ md 이상에서는 텍스트와 이미지를 나란히 배치
p-8
→ 기본 padding
md:p-14
→ md 이상에서는 더 큰 paddingFigma의 Auto Layout과 Constraints로 다시 말하면 이렇습니다.
작은 프레임
→ 세로 오토레이아웃, padding 작게
큰 프레임
→ 가로 배치, padding 크게반응형에서 중요한 것은 모든 화면을 완전히 새로 디자인하는 것이 아닙니다.
무엇은 유지하고, 무엇은 바뀌어야 하는지 규칙을 정하는 것입니다.
유지할 것
- 컴포넌트의 의미
- 콘텐츠 순서
- 브랜드 톤
- 기본 간격 체계
바뀔 것
- 열 개수
- 섹션 padding
- 이미지 위치
- 텍스트 크기디자이너가 이 규칙을 Figma에서 명확히 보여 주면 개발자는 breakpoint를 정하기 쉬워집니다.
CSS Modules와 Tailwind, 무엇을 선택해야 할까
처음 배우는 입장에서는 이렇게 정리하면 됩니다.
| 기준 | CSS Modules | Tailwind CSS |
|---|---|---|
| 스타일 위치 | 별도 .module.css 파일 | JSX의 className 안 |
| 읽는 방식 | 역할 이름 중심 | 시각 속성 중심 |
| Figma 비유 | 컴포넌트 내부 레이어 스타일 | 속성 토큰 칩 조합 |
| 장점 | 구조가 깔끔하고 충돌이 적음 | 빠르게 조합하고 수정하기 쉬움 |
| 부담 | CSS 파일을 오가며 봐야 함 | 클래스가 길어질 수 있음 |
| 잘 맞는 상황 | 복잡한 컴포넌트 스타일, 전통 CSS 선호 | 빠른 UI 제작, 토큰 기반 조합 |
중요한 것은 도구 이름이 아닙니다.
둘 다 결국 같은 질문에 답합니다.
이 색은 어디에서 왔는가?
이 간격은 어떤 기준인가?
이 컴포넌트의 상태는 몇 개인가?
모바일에서 언제 레이아웃이 바뀌는가?디자이너가 Next.js 스타일링을 이해하면 화면을 더 잘 구현하기 위해 개발자가 어떤 결정을 해야 하는지 보입니다.
그리고 핸드오프 문서도 달라집니다.
예전 핸드오프가 이렇게 생겼다면,
카드 padding은 24px입니다.
버튼 색은 보라색입니다.
모바일에서는 한 줄로 쌓아 주세요.이제는 이렇게 말할 수 있습니다.
카드 padding은 spacing scale의 6번 토큰을 사용합니다.
버튼 primary는 color.brand.primary를 사용합니다.
Project Grid는 desktop에서 2열, 760px 이하에서 1열로 전환됩니다.
Button은 primary, secondary, disabled variant가 필요합니다.이 차이는 큽니다.
첫 번째는 화면 설명입니다. 두 번째는 구현 규칙입니다.
작은 실습: 포트폴리오 스타일 규칙 적어 보기
이번 장의 실습은 코드를 많이 쓰는 것보다, 스타일 규칙을 언어로 정리하는 데 초점을 둡니다.
아래 표를 자신의 포트폴리오 기준으로 채워 보세요.
Color
- background:
- surface:
- text:
- text muted:
- brand primary:
- border:
Spacing
- section padding desktop:
- section padding mobile:
- card padding:
- card gap:
- section gap:
Radius
- section radius:
- card radius:
- button radius:
Typography
- hero title desktop:
- hero title mobile:
- body text:
- eyebrow:
Responsive
- project grid desktop:
- project grid mobile:
- breakpoint:예시는 이렇습니다.
Color
- background: #f7f3ee / --color-bg
- surface: #ffffff / --color-surface
- brand primary: #7a5cff / --color-brand
Spacing
- section padding desktop: 48px / --space-12
- section padding mobile: 32px / --space-8
- card gap: 24px / --space-6
Responsive
- project grid desktop: 2 columns
- project grid mobile: 1 column
- breakpoint: 760px이 표는 단순한 메모가 아닙니다.
개발자와 대화할 수 있는 구현 명세의 시작입니다.
Figma에서 화면을 만들 때도 이 표를 옆에 두고 확인해 보세요.
이 28px 간격은 정말 필요한가?
아니면 spacing scale에 없는 예외인가?
이 보라색은 brand primary인가?
아니면 임시로 고른 색인가?
이 카드 radius는 기존 카드와 같은가?디자인 시스템은 거창한 문서에서 시작하지 않습니다.
반복되는 결정을 이름 붙이고, 같은 이름으로 다시 쓰는 것에서 시작합니다.
오늘 배운 멘탈 모델
이번 장에서 가져갈 핵심은 네 가지입니다.
첫째, globals.css는 사이트 전체의 기본 스타일입니다.
globals.css
→ 전체 배경, 기본 글꼴, reset, 공통 토큰둘째, CSS Modules는 특정 페이지나 컴포넌트에만 적용되는 로컬 스타일입니다.
page.module.css
→ page.tsx 전용 스타일셋째, Tailwind는 미리 정해진 스타일 조각을 JSX 안에서 조합하는 방식입니다.
p-6 + rounded-3xl + bg-white + grid
→ padding, radius, background, layout 조합넷째, 반응형은 Figma의 Auto Layout과 Constraints를 코드 규칙으로 옮기는 일입니다.
Desktop 2열
Mobile 1열
→ breakpoint에서 grid 규칙 변경스타일링을 이해하면 개발자처럼 모든 CSS를 직접 짤 필요는 없습니다.
대신 이런 것을 볼 수 있습니다.
디자인 토큰이 코드에 반영되어 있는가?
컴포넌트 스타일이 전역으로 새고 있지 않은가?
모바일 규칙이 Figma와 같은가?
버튼 variant 이름이 디자인과 코드에서 같은가?이것이 디자이너가 Next.js 스타일링을 배워야 하는 이유입니다.
디자이너가 개발자에게 이제 할 수 있는 질문
이번 장을 끝냈다면, 이제 개발자에게 더 구체적인 질문을 할 수 있습니다.
"이 프로젝트는 CSS Modules를 주로 쓰나요, Tailwind를 주로 쓰나요, 아니면 둘을 함께 쓰나요?"
"전역 스타일과 컴포넌트 전용 스타일의 기준은 어떻게 나누고 있나요?"
"Figma의 컬러 변수 이름과 코드의 토큰 이름이 매핑되어 있나요?"
"spacing scale은 어떻게 정의되어 있나요? 예를 들어 4, 8, 12, 16, 24, 32px 같은 규칙이 있나요?"
"예외적인 간격값을 써도 되는 기준이 있나요, 아니면 토큰 안에서만 선택하나요?"
"Tailwind를 쓴다면 기본 scale을 그대로 쓰나요, 우리 디자인 시스템에 맞게 커스터마이즈했나요?"
"ProjectCard의 padding, radius, border는 토큰으로 관리되고 있나요?"
"Button의 primary, secondary, disabled variant는 코드에서도 같은 이름으로 구현되어 있나요?"
"반응형 breakpoint는 몇 px 기준인가요? 모바일, 태블릿, 데스크톱 기준을 어디에서 확인할 수 있나요?"
"프로젝트 카드가 2열에서 1열로 바뀌는 지점은 Figma 시안과 일치하나요?"
"상태에 따라 클래스가 바뀌는 컴포넌트는 어떤 방식으로 관리하나요?
clsx같은 도구를 쓰나요?"
이 질문들은 스타일 취향을 묻는 질문이 아닙니다.
디자인 시스템이 코드 안에서 실제로 유지되는 방식을 확인하는 질문입니다.
다음 장에서는 포트폴리오의 콘텐츠를 코드 안에 직접 적는 방식에서 한 단계 나아갑니다. API가 무엇인지, 외부 데이터가 어떻게 화면으로 들어오는지 살펴보겠습니다.
참고
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.
