1. 왜 SCSS 구조가 중요한가
프로젝트 초기에는 SCSS 파일 하나에 모든 스타일을 몰아넣어도 됩니다. 하지만 페이지가 10개 이상, 컴포넌트가 50개 이상 되면 다음 문제가 발생합니다:
- 특정 컴포넌트 스타일을 수정했는데 다른 페이지가 깨지는 글로벌 충돌
- 어디에 어떤 스타일이 있는지 찾기 어려운 탐색 비용
- 새 팀원이 기존 스타일을 파악하지 못하고 중복 작성하는 증식 문제
체계적인 SCSS 구조는 이를 예방합니다.
2. 권장 파일 구조
resources/scss/ │ ├── _variables.scss # 🎨 디자인 토큰 (색상·여백·타입) ├── _mixins.scss # 🔧 반응형, 유틸리티 믹스인 ├── _common.scss # 🌐 reset, 공통 클래스, 헬퍼 │ ├── pages/ │ ├── _landing.scss # 랜딩 페이지 (body.page-landing) │ ├── _showcase.scss # 쇼케이스 (body.page-showcase) │ ├── _tech.scss # 테크블로그 (body.page-tech) │ ├── _about.scss # 소개 페이지 │ ├── _contact.scss # 문의 페이지 │ └── _faq.scss # FAQ │ ├── components/ # (선택) 여러 페이지에 재사용되는 컴포넌트 │ ├── _navbar.scss │ ├── _footer.scss │ └── _modal.scss │ └── app.scss # 📦 진입점 — Vite가 이 파일만 빌드
3. 페이지 스코프 패턴 — 글로벌 충돌 방지
각 페이지 SCSS 파일은 반드시 body.page-xxx { ... } 안에 모든 스타일을 감쌉니다. 이렇게 하면 다른 페이지 스타일과 충돌이 원천 차단됩니다.
// _showcase.scss
body.page-showcase {
.showcase-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: $space-6;
@include tablet { grid-template-columns: repeat(2, 1fr); }
@include mobile { grid-template-columns: 1fr; }
}
.showcase-card {
background: $brand-surface;
border-radius: $radius-lg;
overflow: hidden;
transition: transform .2s ease;
&:hover { transform: translateY(-4px); }
}
}
body.page-showcase-detail {
.case-hero { background: $brand-dark; color: #fff; }
// ...
}
Blade 레이아웃에서 body 클래스를 동적으로 설정합니다:
{{-- layouts/app.blade.php --}}
<body class="{{ $body_class ?? '' }}">
{{-- 컨트롤러에서 지정 --}}
return view('pages.showcase.index', [
'body_class' => 'page-showcase',
// ...
]);
4. 디자인 토큰 설계 (_variables.scss)
// ── 색상 팔레트 ────────────────────── $brand-cream: #FAFAF8; // 메인 배경 $brand-warm: #F5F0E8; // 섹션 배경 $brand-orange: #C96442; // 주 포인트 $brand-coral: #E8875A; // 호버/강조 $brand-dark: #1C1C1C; // 주 텍스트 $brand-brown: #8B6355; // 보조 텍스트 $brand-border: #E8DDD4; // 경계선 $brand-surface: #FFFFFF; // 카드 배경 // ── 여백 스케일 ────────────────────── $space-1: 4px; $space-2: 8px; $space-3: 12px; $space-4: 16px; $space-5: 20px; $space-6: 24px; $space-7: 32px; $space-8: 40px; $space-9: 48px; $space-10: 64px; $space-11: 80px; $space-12: 96px; // ── 타이포그래피 ────────────────────── $font-sm: 13px; $font-base: 16px; $font-lg: 20px; $font-xl: 28px; $font-2xl: 36px; $font-hero: 48px; $weight-normal: 400; $weight-medium: 500; $weight-bold: 700; $weight-black: 800; // ── 반경 ────────────────────────────── $radius-sm: 6px; $radius-md: 10px; $radius-lg: 16px; $radius-xl: 24px; // ── 그림자 ──────────────────────────── $shadow-sm: 0 2px 8px rgba(0,0,0,.06); $shadow-md: 0 4px 20px rgba(0,0,0,.08); $shadow-lg: 0 8px 40px rgba(0,0,0,.12);
5. Vite 빌드 최적화
// vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
export default defineConfig({
plugins: [
laravel({
input: ['resources/scss/app.scss', 'resources/js/app.js'],
refresh: true, // Blade 변경 시 자동 새로고침
}),
],
css: {
preprocessorOptions: {
scss: {
// 모든 SCSS 파일에 variables와 mixins 자동 주입
// → 각 파일에서 @use 없이 $brand-orange 등 바로 사용 가능
additionalData: `@use "resources/scss/variables" as *;
@use "resources/scss/mixins" as *;`,
}
}
},
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['vue'], // Vue를 별도 청크로 분리
}
}
}
}
});
6. 실무 팁
✅ 할 것
- 변수는 반드시 _variables.scss에
- 페이지별 스타일은 body 클래스 스코프 안에
- 공통 컴포넌트는 components/ 폴더에
- hover는 항상 transition 0.2s ease 추가
❌ 하지 말 것
- app.scss에 직접 스타일 작성
- 인라인 style 속성에 하드코딩 색상
- Bootstrap 유틸리티 클래스 단독 사용
- !important 남발 (명시도 충돌 신호)