관리자 인증 확인 중...
B 또는 Space 로 복귀
LUNA CODE LAB · CLASS II Week 4 — 디자인 시스템 + 인터랙션 고1 · 성인 / 120분
1 / 9 📄 워크시트
WEEK 04 · 2026 · CLASS II

내 사이트의
정체성을 만든다

지난주 인터넷에 띄운 사이트는 — 흔한 템플릿처럼 보입니다. 오늘은 색·폰트·여백·인터랙션을 하나의 시스템으로 묶어 진짜 내 톤으로 다듬습니다.

Duration120 minutes
ToolCSS Variables + IO
Output정체성 박힌 사이트 v2
Phase사이트 다듬기 (1/3)
02 / Learning Goals⏱ 5분

오늘의 학습 목표

1
디자인 시스템 정의
색·폰트·여백을 변수로 정리. CSS Custom Properties로 한 곳에서 관리.
2
컴포넌트 추상화
Button·Card·Section을 재사용 가능한 클래스로. 같은 코드 5번 쓰지 않기.
3
스크롤 애니메이션
Intersection Observer로 아래에서 떠오르는 요소들. 정적 페이지를 살아있게.
4
호버 인터랙션
카드·버튼·메뉴 호버 시 자연스러운 반응. 클릭하고 싶게 만드는 디테일.
03 / Concept⏱ 10분

흔한 템플릿 vs 내 정체성

같은 골격에 — 디자인 시스템 1장만 바꾸면 사이트 인상이 완전히 달라집니다. Linear·Stripe·Notion이 다 다르게 느껴지는 이유 = 각자의 색·폰트·여백·인터랙션 시스템.

🎨
디자인 토큰
color · font
spacing · radius
+
🧩
컴포넌트
Button · Card
Section · Nav
+
인터랙션
Scroll · Hover
Transition
토큰 → 컴포넌트 → 인터랙션 3단 레이어가 디자인 시스템. 한 번 만들면 사이트 어디서나 일관됨, 색 하나 바꾸려고 50군데 고칠 일 없음.
04 / Design Pattern⏱ 15분

즉흥적 vs 시스템 우선

❌ 즉흥적 디자인
"여기 색 좀 바꿔줘"
"이건 더 크게"
"저것도 좀 바꿔주고"
...50번 반복
왜 안 되나? 각 영역마다 색·크기·여백이 다 다름. 일관성 X. 결과: 누덕누덕 사이트, 어디 손대면 다른 곳도 깨짐.
✓ 시스템 먼저 정의
1단계: 색 5개 변수로 정의
2단계: 폰트 3단계 정의
3단계: 여백 5단계 정의
4단계: 컴포넌트에 변수 적용
5단계: 인터랙션 추가
왜 좋나? 변수만 바꾸면 전체 사이트 일관 변경. 컴포넌트 한 번 정의하면 어디든 재사용. 결과: 디자이너 톤, 한 번 만들고 평생 유지보수.
💡 오늘의 비법: "색 → 폰트 → 여백 → 컴포넌트 → 인터랙션" 순서. CSS `:root`에 변수 먼저 박고 그 다음 사용. 거꾸로 가면 안 됨.
05 / Live Build · Step 1⏱ 10분

Step 1 — 컬러 팔레트 정의

Primary(메인) · Secondary(보조) · Accent(액센트) + Neutral 5단계. CSS Variables로 한 곳에 박아두면 색 바꾸기 1초.

1
style.css 또는 index.html <style> 최상단에
:root { /* === Brand Colors === */ --color-primary: #3D5A80; /* 내 메인 색 */ --color-primary-deep: #293B5A; /* 호버·강조용 */ --color-accent: #C4935A; /* 포인트 (CTA·강조) */ /* === Neutrals === */ --color-bg: #FBF7F2; /* 배경 */ --color-text: #3A2E22; /* 본문 */ --color-text-soft: #5F4F3A; /* 보조 텍스트 */ --color-line: rgba(58,46,34,0.12); /* 구분선 */ } /* 사용 예시 */ body { background: var(--color-bg); color: var(--color-text); } .btn { background: var(--color-primary); color: white; }
🎙
멘토 멘트 "색 5개 이상 쓰지 마세요. 3개도 충분해요. 메인 1개 + 액센트 1개 + 글자 색. 색 많으면 어수선해 보여요. 인스타에서 좋아하는 사진 캡처해서 coolors.co에 올리면 자동 추출해줍니다."
🎨
학생 액션 (8분) 무드 이미지 1장 → coolors.co에서 팔레트 추출 → 5개 색 골라서 :root에 변수로 박기 → Claude에 "이 변수들 써서 전체 컬러 통일해줘" → 미리보기.
05 / Live Build · Step 2⏱ 10분

Step 2 — 타이포그래피 시스템

헤드라인·본문·캡션 3단계 크기 + 2종 폰트만으로 충분. 더 늘리면 어수선. Google Fonts에서 1-2개 골라 변수로 박기.

2
폰트 import + 변수 정의
// HTML head에 Google Fonts 추가 (선택한 2개) <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Noto+Serif+KR:wght@700;900&family=Pretendard:wght@400;600;800&display=swap"> /* :root에 추가 */ :root { /* === Typography === */ --font-display: 'Noto Serif KR', serif; /* 큰 헤드라인 */ --font-body: 'Pretendard', sans-serif; /* 본문 */ /* 크기 3단계 — clamp로 반응형 */ --text-display: clamp(36px, 6vw, 64px); --text-heading: clamp(22px, 3vw, 28px); --text-body: 16px; --text-caption: 13px; } h1 { font-family: var(--font-display); font-size: var(--text-display); } h2 { font-family: var(--font-display); font-size: var(--text-heading); } body { font-family: var(--font-body); font-size: var(--text-body); }
🎙
멘토 멘트 "폰트 2개 이상 쓰면 안 예뻐요. Serif 1개(큰 글자) + Sans 1개(본문) — 이게 황금률. 한글 폰트는 Pretendard, Gmarket Sans, IBM Plex Sans KR 3개 중에 골라요. 한 번 결정하고 끝까지 가세요."
🔤
학생 액션 (8분) Google Fonts에서 폰트 2개 고르기 → link 태그 추가 → --font-display, --font-body 변수 박기 → Claude에 "h1·h2·body에 이 변수 적용해줘" → 미리보기에서 확인.
05 / Live Build · Step 3⏱ 15분

Step 3 — 컴포넌트 추상화

Button·Card·Section을 재사용 가능한 클래스로. 카드 5개 만들 때 같은 CSS 5번 X — 클래스 1개로 5번 적용.

3
Button 컴포넌트 정의
/* 모든 버튼은 .btn 베이스 + variant 클래스로 */ .btn { display: inline-flex; align-items: center; gap: 8px; padding: var(--space-3) var(--space-5); border-radius: 12px; font-weight: 700; cursor: pointer; transition: transform .2s, box-shadow .2s; } .btn-primary { background: var(--color-primary); color: white; } .btn-ghost { background: transparent; border: 1px solid var(--color-line); } .btn:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0,0,0,.1); } /* HTML에서는 — 한 번 정의, 어디서나 사용 */ <a class="btn btn-primary">Works 보기</a> <a class="btn btn-ghost">About</a>
🧩
Card · Section 컴포넌트
.card { background: white; border-radius: 16px; padding: var(--space-5); border: 1px solid var(--color-line); transition: all .25s; } .card:hover { transform: translateY(-4px); border-color: var(--color-primary); } .section { padding: var(--space-9) 0; } .section-title { font-size: var(--text-heading); margin-bottom: var(--space-5); } /* 여백 변수도 8px 베이스로 정의 */ :root { --space-1: 4px; --space-3: 12px; --space-5: 24px; --space-7: 48px; --space-9: 80px; }
🎙
멘토 멘트 "같은 코드 2번 쓰면 컴포넌트로 묶으세요. 3번 쓰면 반드시. 이걸 'DRY 원칙'이라고 해요. 처음엔 귀찮아도 사이트가 커지면 — 색 하나 바꾸려고 50군데 고치지 않아도 돼요."
🧩
학생 액션 (12분) Claude에 "내 사이트 코드 분석해서 .btn / .card / .section 3개 컴포넌트로 묶고 모든 자리에 적용해줘" → 미리보기 → 일관성 확인 → 5개 이상 컴포넌트 만들어보기.
05 / Live Build · Step 4⏱ 15분

Step 4 — 스크롤 애니메이션

정적인 페이지가 스크롤 따라 살아나는 마법. Intersection Observer로 화면에 들어올 때 fade-in. 한 번 정의하면 모든 요소에 .reveal 클래스만 추가.

4
CSS — 초기 상태 + 떠오르는 상태
.reveal { /* 초기: 30px 아래 + 투명 */ opacity: 0; transform: translateY(30px); transition: opacity .8s ease, transform .8s ease; } .reveal.in-view { /* 화면 들어오면: 원위치 + 보임 */ opacity: 1; transform: translateY(0); } /* 딜레이 변형 — 카드들 순차 등장 */ .reveal.delay-1 { transition-delay: .1s; } .reveal.delay-2 { transition-delay: .2s; } .reveal.delay-3 { transition-delay: .3s; }
⚙️
JS — Intersection Observer 한 번 정의
<script> // 화면에 보이는지 감시하는 Observer 만들기 const io = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('in-view'); io.unobserve(entry.target); // 한 번만 트리거 } }); }, { threshold: 0.15 }); // 15% 보이면 트리거 // 모든 .reveal 요소에 적용 document.querySelectorAll('.reveal').forEach(el => io.observe(el)); </script> <!-- HTML에서 — 그냥 클래스만 추가 --> <div class="card reveal delay-1">...</div> <div class="card reveal delay-2">...</div>
🎙
멘토 멘트 "옛날엔 jQuery로 스크롤 위치 계산하느라 힘들었어요. 지금은 Intersection Observer 10줄이면 끝. 너무 많이 쓰면 어지러우니까 — 카드·섹션 제목 정도만. 본문 텍스트 하나하나에 다 넣으면 멀미해요."
학생 액션 (12분) Claude에 ".reveal 시스템 + Intersection Observer 만들고, 갤러리 카드·섹션 제목에 .reveal 클래스 적용해줘" → 새로고침 → 스크롤하면서 카드 떠오르는지 확인.
05 / Live Build · Step 5⏱ 10분

Step 5 — 호버 인터랙션

"마우스 올려보고 싶다"의 미세 디테일. 카드 transform · 버튼 그림자 · 메뉴 밑줄이 사이트를 살아있게 만든다. 과하지 않게 살짝만.

5a
카드·버튼·메뉴 호버 효과 3종
/* ① 카드 — 살짝 떠오르며 그림자 진해짐 */ .card { transition: all .25s ease; } .card:hover { transform: translateY(-6px); box-shadow: 0 16px 40px rgba(58,46,34,.12); border-color: var(--color-primary); } /* ② 버튼 — 색 진해지며 그림자 */ .btn-primary:hover { background: var(--color-primary-deep); box-shadow: 0 8px 24px rgba(61,90,128,.35); transform: translateY(-2px); } /* ③ 메뉴 — 밑줄 슬라이드 인 */ .nav-link { position: relative; padding-bottom: 4px; } .nav-link::after { content: ''; position: absolute; left: 0; bottom: 0; width: 0; height: 2px; background: var(--color-accent); transition: width .3s ease; } .nav-link:hover::after { width: 100%; }
최종 점검 5가지
□ 색 변수 5개 + 사이트 전체에 var() 적용 □ 폰트 2개 + 크기 3단계 변수로 □ 컴포넌트 5개+ (btn·card·section 등) □ 스크롤 시 카드 fade-in 작동 □ 카드·버튼·메뉴 호버 살짝 반응
🎙
오늘의 마무리 "호버는 0.2~0.3초가 황금률. 더 느리면 답답, 더 빠르면 안 보임. transform: translateY(-2px~-6px) 정도가 자연스러워요. 다 끝나면 firebase deploy 한 번 더! 친구한테 'v2 봐줘' 다시 카톡."
💫
학생 액션 (8분) Claude에 "카드·버튼·메뉴 호버 효과 추가해줘" → 미리보기 → firebase deploy → 휴대폰 + PC 둘 다 확인 → 친구한테 v2 자랑.
10 / Checkpoint⏱ 5분

디자인 점검 5가지

오늘 잘 됐다면
  • :root 변수 색 5개·폰트 2개·여백 5단계 박힘
  • 사이트 어디서나 var() 사용 — 직접 색·px 입력 X
  • 컴포넌트 5개 이상 (.btn·.card·.section…)
  • 스크롤 시 카드 fade-in — IntersectionObserver 작동
  • 카드·버튼·메뉴 호버 자연스럽게 반응
⚠️자주 막히는 부분
  • 색 5개 이상 사용 → 메인 1·보조 1·액센트 1·중성 2로 줄이기
  • 폰트 3개+ → display 1 + body 1 두 개만
  • 같은 CSS 여러 번 반복 → 컴포넌트 클래스로 묶기
  • scroll 애니메이션 X → IO 코드 script 태그 끝 부분에 위치, defer 안 걸렸는지 확인
  • 호버 너무 과함 → translateY 6px·transition 0.25s 이하로
11 / Challenge⏱ 10분

디자인 깊이 도전

🌗
다크모드 토글 — :root에 라이트 색, [data-theme="dark"]에 다크 색 정의. 우상단 버튼으로 전환, localStorage에 선택 저장.
난이도 ★
📄
페이지 전환 애니메이션 — about·works 페이지 클릭 시 fade 또는 slide. View Transitions API 사용.
난이도 ★★
🖱
마우스 따라 그라디언트 — 히어로 영역에 마우스 위치 추적해서 spotlight 효과. CSS conic-gradient + JS mousemove.
난이도 ★★★
12 / Student Gallery⏱ 7분

작년 친구들 작품

13 / Next Week⏱ 5분

다음 시간 예고

WEEK 05 · COMING UP

Suno로
내 사이트 BGM 작곡

사이트가 다듬어졌으니 — 이제 나만의 BGM이 들어갑니다. AI 작곡 도구 Suno로 1시간 안에 자기 곡 첫 컷. 장르·BPM·무드를 디렉팅해서 사이트에 맞는 BGM 한 곡.

PREPARE · 다음 주 준비물
  • 오늘 다듬은 사이트 URL (BGM 분위기 정할 때 참고)
  • Suno 계정 미리 가입 (suno.com, Google 계정 OK)
  • 좋아하는 장르 키워드 5개 (lo-fi, ambient, indie pop, jazz, electronic 등)
  • 레퍼런스 곡 YouTube 링크 2-3개 (이런 분위기 만들고 싶다)
  • 이어폰·헤드폰 필수 — 음악 작업 + 비교 청취