1. 왜 SCSS를 쓰는가
CSS는 강력하지만, 대규모 프로젝트에서는 관리하기 어렵습니다. 색상값을 100개 파일에 하드코딩했다가 브랜드 색이 바뀌면 전체 검색·치환을 해야 합니다. SCSS는 이 문제를 변수, 중첩, 함수로 해결합니다.
// ❌ 일반 CSS — 색상을 30개 파일에 반복
.btn { background: #C96442; }
.link { color: #C96442; }
.badge { border-color: #C96442; }
// ✅ SCSS — 변수 하나로 관리
$brand-orange: #C96442;
.btn { background: $brand-orange; }
.link { color: $brand-orange; }
.badge { border-color: $brand-orange; }
2. 변수 ($)
SCSS 변수는 $로 시작합니다. 색상, 여백, 폰트 크기 등 반복되는 값을 관리합니다.
// _variables.scss $brand-cream: #FAFAF8; $brand-orange: #C96442; $brand-dark: #1C1C1C; $space-1: 4px; $space-2: 8px; $space-4: 16px; $space-6: 24px; $space-8: 32px; $space-9: 48px; $space-10: 64px; $radius-sm: 8px; $radius-md: 12px; $radius-lg: 20px; $font-sm: 13px; $font-base: 16px; $font-lg: 20px; $font-xl: 28px; $font-2xl: 36px; $font-hero: 48px;
3. 중첩 (Nesting)
CSS 선택자를 중첩하여 구조를 시각적으로 표현합니다. HTML 구조와 SCSS 구조가 일치하면 유지보수가 쉬워집니다.
// ✅ SCSS 중첩
.nav-bar {
background: $brand-dark;
padding: $space-4 0;
.nav-logo {
font-size: $font-lg;
color: #fff;
}
.nav-link {
color: rgba(#fff, .7);
&:hover { color: #fff; } // & = 부모 선택자
&.is-active { color: $brand-orange; }
}
@media (max-width: 768px) { // 반응형도 중첩 가능
padding: $space-2 0;
}
}
// 컴파일된 CSS
.nav-bar { background: #1C1C1C; }
.nav-bar .nav-link { color: rgba(255,255,255,.7); }
.nav-bar .nav-link:hover { color: #fff; }
4. Mixin & Include
반복되는 CSS 블록을 함수처럼 재사용합니다. 파라미터를 받아서 동적으로 스타일을 생성할 수 있습니다.
// _mixins.scss 정의
@mixin flex-center {
display: flex;
align-items: center;
justify-content: center;
}
@mixin responsive($bp) {
@if $bp == 'tablet' { @media (max-width: 1024px) { @content; } }
@if $bp == 'mobile' { @media (max-width: 768px) { @content; } }
}
@mixin button-variant($bg, $color: #fff) {
background: $bg;
color: $color;
&:hover { background: lighten($bg, 8%); }
}
// 사용
.hero-visual {
@include flex-center;
height: 400px;
@include responsive('tablet') {
height: 260px;
}
}
.btn-primary { @include button-variant($brand-orange); }
.btn-ghost { @include button-variant(transparent, $brand-dark); }
5. @extend & %placeholder
%placeholder는 컴파일 시 CSS에 포함되지 않는 재사용 블록입니다. @extend로 스타일을 상속합니다.
%card-base {
background: #fff;
border-radius: $radius-lg;
box-shadow: 0 4px 20px rgba(0,0,0,.06);
padding: $space-6;
}
.tech-card { @extend %card-base; border-top: 3px solid $brand-orange; }
.service-card { @extend %card-base; &:hover { transform: translateY(-4px); } }
.case-card { @extend %card-base; min-height: 200px; }
6. @use & @forward (Sass 모듈 시스템)
구버전의 @import 대신 @use와 @forward를 사용하는 것이 현대 SCSS의 표준입니다.
// app.scss — 진입점 @use 'variables' as *; // as *: 접두사 없이 $brand-orange 직접 사용 @use 'mixins' as *; @use 'common'; // 페이지별 스타일 @use 'pages/landing'; @use 'pages/showcase'; @use 'pages/tech'; // _index.scss — 폴더 하위 파일들을 한 번에 export (선택적) @forward 'variables'; @forward 'mixins';
7. 실무 파일 구조
resources/scss/
_variables.scss ← 색상, 여백, 폰트 변수
_mixins.scss ← 반응형, flex, 버튼 믹스인
_common.scss ← reset, body, 공통 유틸리티
pages/
_landing.scss ← body.page-landing 전용
_showcase.scss ← body.page-showcase 전용
_tech.scss ← body.page-tech 전용
_contact.scss
app.scss ← 전체 @use 진입점 (Vite가 이 파일을 빌드)
// app.scss 예시
@use 'variables' as *;
@use 'mixins' as *;
@use 'common';
@use 'pages/landing';
@use 'pages/showcase';
@use 'pages/tech';
✅ SCSS 작성 원칙 (BEM + 페이지 스코프)
- 페이지별 스타일은 반드시
body.page-xxx { ... }안에 작성 (전역 충돌 방지) - 컴포넌트 클래스명:
showcase-card,tech-post-title(kebab-case) - 상태 클래스:
is-active,is-visible,has-error - JS 전용 클래스:
js-접두사로 CSS와 분리