실무에서는 수천 줄의 SCSS를 한 파일에 작성하지 않습니다. 변수, 믹스인, 리셋, 레이아웃, 컴포넌트 별로 파일을 쪼개서 관리합니다. 파일명 앞에 언더스코어(_)를 붙이면 독립적인 CSS 파일로 컴파일되지 않는 '부분 파일(Partial)'이 됩니다.
메인 파일인 style.scss에서 @use 키워드를 사용해 조각난 파일들을 하나로 불러와 조립합니다. (과거에는 @import를 썼지만, 이름 충돌 문제로 현재는 @use를 권장합니다.)
| 폴더명 (7-1 Pattern 예시) | 포함되는 파일 (Partials) | 역할 설명 |
|---|---|---|
| abstracts/ | _variables.scss, _mixins.scss |
실제 CSS 코드는 출력하지 않고 변수와 믹스인만 정의 |
| base/ | _reset.scss, _typography.scss |
HTML 태그 기본 스타일 및 웹 폰트 초기화 |
| components/ | _buttons.scss, _cards.scss |
재사용 가능한 UI 컴포넌트 단위의 스타일 |
| layout/ | _header.scss, _footer.scss |
사이트의 전반적인 골격과 레이아웃 스타일 |
파일명 앞에 언더스코어(_)를 붙여 부분 파일(Partial)을 만들고, 메인 파일에서 @use로 불러옵니다. 불러올 때 자동으로 네임스페이스가 생성되며, as 키워드를 사용해 네임스페이스를 원하는 대로 변경할 수 있습니다.
$primary: #4f46e5;
$font-stack: 'Helvetica Neue', sans-serif;
@mixin box-shadow {
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
// 불러올 때 확장자(.scss)와 언더스코어(_)는 생략 가능합니다.
@use 'variables' as v;
@use 'mixins' as m;
.module-test {
// 네임스페이스(v., m.)를 통해 접근하므로 이름 충돌이 절대 발생하지 않습니다!
font-family: v.$font-stack;
color: v.$primary;
@include m.box-shadow;
padding: 20px;
border-radius: 8px;
}
.module-test {
font-family: "Helvetica Neue", sans-serif;
color: #4f46e5;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
padding: 20px;
border-radius: 8px;
}
파일이 많아지면 @use를 수십 번 작성해야 해서 불편할 수 있습니다. 이럴 때 @forward를 사용하면 여러 부분 파일들을 하나의 진입점(Entry point) 파일로 묶어서 다른 곳에 일괄 내보낼 수 있습니다. (JavaScript의 export * from '...' 패턴과 유사합니다.)
/* 여러 파일을 묶어서 내보냅니다. */
@forward 'variables';
@forward 'mixins';
@forward 'functions';
/* 이제 main.scss에서는 abstracts 폴더만 한 번 @use로 불러오면
모든 변수와 믹스인을 한꺼번에 사용할 수 있습니다! */
Sass 공식 문서에 따르면 @import는 전역 스코프 오염과 중복 컴파일로 인한 성능 문제 때문에 조만간 완전히 폐기될 예정입니다. 새로 작성하는 모든 프로젝트에서는 반드시 @use를 사용해야 하며, 네임스페이스를 통해 명시적으로 변수와 믹스인에 접근해야 합니다.
버튼을 마우스로 호버했을 때 조금 더 어두운 색으로 만들고 싶다면? 포토샵을 열어 헥스 코드(Hex)를 찾을 필요가 없습니다.
SCSS는 자체적으로 수학 계산과 색상 조작을 위한 강력한 내장 함수(Built-in Functions)를 제공합니다. darken(), lighten(), rgba() 등의 함수를 활용하면 단일 메인 컬러 변수 하나만으로도 수십 가지의 파생 컬러 시스템을 자동으로 구축할 수 있습니다.
| 함수명 | 역할 | 사용 예시 |
|---|---|---|
| darken() | 주어진 색상을 특정 비율만큼 어둡게 만듭니다. | darken($primary, 10%) |
| lighten() | 주어진 색상을 특정 비율만큼 밝게 만듭니다. | lighten($primary, 20%) |
| rgba() | 헥스 색상에 투명도(Alpha)를 추가합니다. | rgba($primary, 0.5) |
<div class="btn-group">
<button class="btn-color">기본 상태</button>
<button class="btn-color hover-sim">Hover 상태 (15% 어두워짐)</button>
<button class="btn-color active-sim">Active 상태 (20% 더 어두워짐)</button>
</div>
/* SCSS 내장 함수 예시 */
/*
$theme-color: #38bdf8; // 밝은 하늘색
.btn-color {
background-color: $theme-color;
color: white;
padding: 12px 24px;
border: none;
border-radius: 6px;
cursor: pointer;
transition: background-color 0.2s;
&:hover {
// 기존 색상에서 15% 어둡게 만듭니다.
background-color: darken($theme-color, 15%);
}
&:active {
background-color: darken($theme-color, 25%);
}
}
// 브라우저 결과를 보여주기 위한 시뮬레이션 클래스
.hover-sim {
background-color: darken($theme-color, 15%);
}
.active-sim {
background-color: darken($theme-color, 25%);
}
*/
/* 컴파일된 실제 CSS */
.btn-group {
display: flex; gap: 10px; padding: 20px;
}
.btn-color {
background-color: #38bdf8;
color: white;
padding: 12px 24px;
border: none;
border-radius: 6px;
cursor: pointer;
transition: background-color 0.2s;
}
.btn-color:hover, .hover-sim {
background-color: #069cdb; /* 어두워진 색상 자동 계산 */
}
.btn-color:active, .active-sim {
background-color: #046b96; /* 더 어두워진 색상 */
}
웹 프로젝트가 커지면서 기존 CSS만으로는 코드가 수천 줄로 늘어나고 관리가 불가능해지는 문제(유지보수 지옥)가 발생했습니다.
이러한 불편함을 해소하기 위해 등장한 것이 바로 CSS 전처리기(Preprocessor)인 SCSS(Sassy CSS)입니다. SCSS는 변수, 중첩, 반복문, 함수 등 프로그래밍 언어의 특징을 CSS에 도입하여 코드를 획기적으로 줄이고 재사용성을 극대화합니다.
| 특징 | 기존 CSS | SCSS (Sassy CSS) |
|---|---|---|
| 유지보수 | 어려움 (코드 중복 심함) | 쉬움 (변수와 모듈화) |
| 구조화 | 평면적이고 반복적 | 계층적 (Nesting 지원) |
브라우저는 오직 순수 CSS만 해석할 수 있습니다. 따라서 SCSS로 작성된 코드는 반드시 컴파일(Compile) 과정을 거쳐 일반 CSS 파일로 변환되어야 합니다.
<!-- SCSS는 개발 환경에서만 작성되고, 브라우저에는 컴파일된 CSS가 적용됩니다. -->
<div class="card">
<h2>SCSS 컴파일 결과 확인</h2>
<button class="btn primary">확인</button>
<button class="btn danger">취소</button>
</div>
/* 아래 코드는 SCSS가 일반 CSS로 컴파일된 결과입니다. */
.card {
padding: 20px;
background-color: #f8f9fa;
border-radius: 8px;
}
.card h2 {
color: #333;
}
.btn {
padding: 10px 20px;
border: none;
border-radius: 4px;
font-weight: bold;
cursor: pointer;
}
.btn.primary {
background-color: #007bff;
color: white;
}
.btn.danger {
background-color: #dc3545;
color: white;
}
웹사이트의 브랜드 컬러를 변경해야 한다고 상상해보세요. 기존 CSS에서는 #3b82f6 색상을 사용한 500군데를 모두 찾아 일일이 수정해야 합니다.
SCSS에서는 $ 기호를 사용하여 색상, 폰트 사이즈, 여백 등을 변수로 저장할 수 있습니다. 변수 값 하나만 수정하면 사이트 전체의 스타일이 한 번에 변경됩니다!
| 변수 타입 | SCSS 코드 예시 |
|---|---|
| 색상 (Colors) | $primary: #ff0000;, $bg-color: rgba(0,0,0,0.5); |
| 폰트 (Typography) | $font-stack: 'Pretendard', sans-serif;, $h1-size: 2rem; |
| 크기/단위 (Sizes) | $container-width: 1200px;, $border-radius: 8px; |
<div class="profile-card">
<h2 class="profile-name">홍길동</h2>
<p class="profile-desc">프론트엔드 개발자</p>
<button class="profile-btn">팔로우</button>
</div>
/* SCSS 작성 예시 (컴파일 후 모습) */
/*
$brand-color: #8b5cf6;
$text-color: #1f2937;
$border-radius: 12px;
*/
.profile-card {
padding: 20px;
border-radius: 12px; /* $border-radius */
border: 2px solid #8b5cf6; /* $brand-color */
text-align: center;
max-width: 300px;
}
.profile-name {
color: #8b5cf6; /* $brand-color */
margin-bottom: 5px;
}
.profile-desc {
color: #1f2937; /* $text-color */
}
.profile-btn {
background-color: #8b5cf6; /* $brand-color */
color: white;
border: none;
border-radius: 12px; /* $border-radius */
padding: 10px 20px;
margin-top: 15px;
cursor: pointer;
transition: opacity 0.2s;
}
.profile-btn:hover {
opacity: 0.8;
}
기존 CSS에서는 HTML의 계층 구조를 표현하기 위해 선택자를 매번 처음부터 길게 반복해서 적어야 했습니다.
SCSS의 Nesting(중첩)을 사용하면 HTML과 동일한 시각적 계층 구조로 CSS를 작성할 수 있습니다. 상위 선택자 안에 하위 선택자를 포함시켜 가독성을 크게 높이고 타이핑 양을 줄여줍니다. 부모 선택자를 가리키는 & 기호와 결합하면 더욱 강력해집니다.
HTML 구조와 똑같이 만든답시고 4~5단계 이상 깊게 중첩하게 되면, 컴파일된 CSS의 구체성(Specificity)이 너무 높아져 스타일을 덮어쓰기 매우 힘들어집니다. 중첩은 가급적 3단계를 넘지 않도록 작성하는 것이 모범 사례입니다.
<nav class="navigation">
<ul class="nav-list">
<li class="nav-item"><a href="#">홈</a></li>
<li class="nav-item"><a href="#">소개</a></li>
<li class="nav-item active"><a href="#">서비스</a></li>
</ul>
</nav>
/* SCSS 중첩 구조 예시 (컴파일된 CSS) */
/*
.navigation {
background: #333;
padding: 1rem;
.nav-list {
display: flex;
gap: 1rem;
list-style: none;
margin: 0; padding: 0;
}
.nav-item {
a {
color: white;
text-decoration: none;
&:hover {
color: #61dafb; // & 기호는 부모(a)를 그대로 치환함
}
}
&.active a {
font-weight: bold;
color: #61dafb;
}
}
}
*/
/* 컴파일된 실제 CSS */
.navigation {
background: #333;
padding: 1rem;
}
.navigation .nav-list {
display: flex;
gap: 1rem;
list-style: none;
margin: 0;
padding: 0;
}
.navigation .nav-item a {
color: white;
text-decoration: none;
}
.navigation .nav-item a:hover {
color: #61dafb;
}
.navigation .nav-item.active a {
font-weight: bold;
color: #61dafb;
}
flexbox 중앙 정렬이나 버튼 스타일처럼 똑같은 CSS 코드 뭉치를 여러 곳에서 반복해서 치고 있진 않나요?
Mixin(믹스인)은 재사용 가능한 코드 블록을 도장처럼 만들어두고 필요할 때마다 찍어내는 기능입니다. 특히 함수처럼 인자(Argument)를 전달받을 수 있어서, 똑같은 구조지만 색상이나 크기만 다른 요소를 찍어낼 때 진가를 발휘합니다.
| 키워드 | 역할 | 사용 예시 |
|---|---|---|
| @mixin | 재사용할 스타일 블록을 정의 | @mixin flex-center { display: flex; ... } |
| @include | 정의된 믹스인을 호출하여 포함 | .box { @include flex-center; } |
| 인자 (Args) | 믹스인에 동적인 값을 전달 | @mixin button($color) { background: $color; } |
<div class="box-container">
<div class="box-small">Small Box</div>
<div class="box-large">Large Box</div>
</div>
/* SCSS Mixin 예시 */
/*
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
@mixin circle($size, $color) {
width: $size;
height: $size;
background-color: $color;
border-radius: 50%;
color: white;
@include flex-center; // Mixin 안에서 다른 Mixin 호출 가능!
}
.box-small {
@include circle(100px, #ef4444);
}
.box-large {
@include circle(150px, #3b82f6);
}
*/
/* 컴파일된 실제 CSS */
.box-container {
display: flex;
gap: 20px;
padding: 20px;
}
.box-small {
width: 100px;
height: 100px;
background-color: #ef4444;
border-radius: 50%;
color: white;
display: flex;
justify-content: center;
align-items: center;
}
.box-large {
width: 150px;
height: 150px;
background-color: #3b82f6;
border-radius: 50%;
color: white;
display: flex;
justify-content: center;
align-items: center;
}
특정 클래스의 스타일을 다른 클래스에서 그대로 물려받아 사용하고 싶을 때가 있습니다. (예: 기본 버튼의 형태를 물려받고 색상만 다른 에러 버튼)
@extend 키워드를 사용하면, 다른 선택자의 규칙을 상속받을 수 있습니다. 컴파일 시 중복되는 코드를 생성하지 않고 선택자들을 그룹화(, 로 연결)하여 CSS 용량을 최적화하는 데 도움을 줍니다.
// %를 붙이면 CSS로 컴파일되지 않는 추상 클래스가 됩니다.
%message-shared {
padding: 15px;
border: 1px solid #ccc;
border-radius: 8px;
}
.msg-success {
@extend %message-shared;
background-color: #d1fae5;
}
.msg-error {
@extend %message-shared;
background-color: #fee2e2;
}
/* 컴파일된 실제 CSS (선택자가 , 로 묶인 것을 확인하세요!) */
.msg-error, .msg-success {
padding: 15px;
border: 1px solid #ccc;
border-radius: 8px;
}
.msg-success {
background-color: #d1fae5;
}
.msg-error {
background-color: #fee2e2;
}
@extend를 사용할 때 일반 클래스를 상속할 수도 있지만, 주로 플레이스홀더(%)를 사용합니다. 두 방식의 컴파일 결과는 어떻게 다를까요?
.btn-base { padding: 10px; }
.btn-red {
@extend .btn-base;
color: red;
}
/* --- 컴파일 결과 --- */
.btn-base, .btn-red { padding: 10px; }
.btn-red { color: red; }
/* .btn-base가 단독으로 쓰이지 않아도
CSS 파일에 강제로 렌더링되어 용량을 차지합니다. */
%btn-base { padding: 10px; }
.btn-red {
@extend %btn-base;
color: red;
}
/* --- 컴파일 결과 --- */
.btn-red { padding: 10px; }
.btn-red { color: red; }
/* %btn-base 본체는 컴파일시 흔적 없이 사라지고,
오직 상속받은 클래스만 남습니다. (용량 최적화) */
하나의 클래스가 여러 개의 속성을 동시에 상속받을 수도 있습니다.
%box-shadow { box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
%rounded-corner { border-radius: 12px; }
.custom-card {
@extend %box-shadow; // 여러 번 사용 가능
@extend %rounded-corner;
background-color: white;
}
중첩된(Nested) 구조 안에서 무분별하게 @extend를 사용하면, SCSS 컴파일러가 모든 가능한 경우의 수를 계산하여 콤마(,)로 묶어버립니다. 이로 인해 컴파일된 CSS 용량이 기하급수적으로 늘어나고 디버깅이 불가능해집니다.
/* 😱 아주 끔찍한 상황 예시 */
.admin-panel .btn { @extend .btn-primary; }
.user-dashboard .btn { @extend .btn-primary; }
.modal-window .action-btn { @extend .btn-primary; }
/* .btn-primary가 호버 상태(:hover) 등을 가지고 있다면?
컴파일 시 아래와 같이 무수한 선택자 조합이 탄생합니다. */
.btn-primary:hover,
.admin-panel .btn:hover,
.user-dashboard .btn:hover,
.modal-window .action-btn:hover {
background-color: darkblue;
}
/* 프로젝트 규모가 커질수록 이 콤마(,) 조합은 수십, 수백 줄로 뻥튀기됩니다! */
위에서 살펴본 선택자 폭발 부작용과 코드 순서 예측의 어려움 때문에, 최신 SCSS 가이드라인에서는 가급적 @extend의 사용을 지양하고 매개변수 활용이 가능한 @mixin을 사용할 것을 강력히 권장하고 있습니다. (레거시 코드를 읽기 위해 작동 원리만 이해해 두세요!)
반응형 웹을 만들 때마다 모바일, 태블릿, 데스크탑의 픽셀(px) 중단점(Breakpoint)을 기억하고 매번 타이핑하기는 매우 고통스럽습니다.
믹스인의 특별한 지시어인 @content를 활용하면, 미디어 쿼리의 뼈대를 미리 만들어두고 그 내부에 원하는 스타일 블록을 나중에 동적으로 주입할 수 있습니다. 이를 통해 반응형 코드를 극도로 직관적이고 깔끔하게 관리할 수 있습니다.
@content는 마치 React의 {children}이나 Vue의 <slot>과 같은 역할을 합니다. 믹스인을 호출할 때 중괄호 {} 안에 작성한 CSS 코드 덩어리 전체를 @content 위치에 통째로 렌더링해 줍니다.
<div class="hero-section">
<h1>반응형 웹사이트 만들기</h1>
<p>창 크기를 줄여보세요!</p>
</div>
/* SCSS 반응형 믹스인 설계 */
/*
// 1. 브레이크포인트 변수 선언
$bp-mobile: 768px;
$bp-tablet: 1024px;
// 2. 미디어 쿼리 믹스인 생성 (@content 가 핵심!)
@mixin mobile {
@media (max-width: #{$bp-mobile}) {
@content; // mixin을 호출할 때 넘겨준 중괄호 {} 안의 내용이 이 자리에 들어갑니다.
}
}
@mixin tablet {
@media (max-width: #{$bp-tablet}) {
@content;
}
}
// 3. 실제 적용
.hero-section {
padding: 100px 50px;
background-color: #f1f5f9;
text-align: center;
font-size: 24px;
// 관련 코드를 분산시키지 않고 이 블록 안에서 바로 반응형 처리!
@include tablet {
padding: 80px 30px;
font-size: 20px;
}
@include mobile {
padding: 50px 15px;
background-color: #cbd5e1; // 모바일에서는 배경색도 변경
font-size: 16px;
}
}
*/
/* 컴파일된 실제 CSS */
.hero-section {
padding: 100px 50px;
background-color: #f1f5f9;
text-align: center;
font-size: 24px;
}
@media (max-width: 1024px) {
.hero-section {
padding: 80px 30px;
font-size: 20px;
}
}
@media (max-width: 768px) {
.hero-section {
padding: 50px 15px;
background-color: #cbd5e1;
font-size: 16px;
}
}
BEM은 .card__title--active 처럼 클래스명으로 부모-자식 관계와 상태를 명확히 나타내는 CSS 네이밍 컨벤션입니다. 하지만 순수 CSS에서는 클래스명이 너무 길어져 타이핑하기 번거롭습니다.
SCSS의 부모 참조 연산자 &를 BEM과 결합하면, 중첩(Nesting)의 깊이를 1단계로 유지하면서도 BEM 클래스명을 자동으로 생성할 수 있어 코드의 가독성과 유지보수성이 극대화됩니다.
| 구성요소 | 구분자 | 설명 및 예시 |
|---|---|---|
| Block (블록) | 없음 | 독립적으로 의미를 가지는 최상위 컴포넌트 (예: .card, .nav) |
| Element (요소) | __ (언더스코어 2개) | 블록 내부에 종속된 하위 요소 (예: .card__title, .nav__item) |
| Modifier (상태) | -- (하이픈 2개) | 블록이나 요소의 모양/상태 변경 (예: .card--dark, .nav__item--active) |
& 연산자를 사용하여 부모 선택자를 참조하면, 컴파일 시 부모 이름이 문자열로 치환되며 BEM 클래스명이 완성됩니다.
<!-- BEM 방식으로 작성된 제품 카드 -->
<article class="product-card">
<div class="product-card__content">
<h2 class="product-card__title">최신형 노트북</h2>
<p class="product-card__price product-card__price--discount">1,200,000원</p>
</div>
<button class="product-card__button">구매하기</button>
</article>
/* SCSS 작성법 (& 기호가 .product-card 로 치환됨) */
.product-card {
border: 1px solid #ddd;
border-radius: 8px;
max-width: 300px;
/* Element */
&__content {
padding: 20px;
}
&__title {
font-size: 1.25rem;
font-weight: bold;
}
&__price {
color: #333;
/* Modifier: 상태나 변형은 &-- 로 연결 */
&--discount {
color: #ef4444;
font-weight: bold;
text-decoration: underline;
}
}
/* 가상 클래스(Pseudo-class)도 &로 연결 */
&__button {
background: #3b82f6;
color: white;
&:hover {
background: #2563eb;
}
}
}
실무에서는 &__나 &--를 매번 타이핑하는 대신, Mixin과 문자열 보간(Interpolation, #{})을 활용해 BEM 구조를 함수처럼 강제하는 아키텍처를 많이 사용합니다. 이 방법을 사용하면 팀원들이 실수로 잘못된 BEM 컨벤션을 사용하는 것을 원천 차단할 수 있습니다.
/* BEM 제어용 믹스인 정의 */
@mixin e($element) {
&__#{$element} {
@content;
}
}
@mixin m($modifier) {
&--#{$modifier} {
@content;
}
}
/* 믹스인 활용 예시 */
.product-card {
/* @include e('content')는 결국 &__content 와 동일합니다. */
@include e('content') {
padding: 20px;
}
@include e('price') {
color: #333;
@include m('discount') {
color: #ef4444;
}
}
}
초보자들이 가장 많이 하는 실수는 HTML 구조와 똑같이 4단계, 5단계 이상 중첩하는 것입니다. (예: .nav { ul { li { a { span { ... } } } } }) 이렇게 하면 컴파일된 CSS의 구체성(Specificity)이 불필요하게 높아져 스타일 덮어쓰기가 매우 힘들어집니다. 중첩은 최대 3단계를 넘지 않는 것이 좋으며, BEM을 사용하면 1단계로 평탄화할 수 있습니다.
CSS는 프로그래밍 언어가 아니기 때문에 조건에 따라 스타일을 바꾸거나 수십 개의 클래스를 반복해서 생성하는 것이 불가능했습니다.
SCSS는 프로그래밍 언어의 제어문(Control Flow)을 완벽하게 지원합니다. @if로 다크모드 여부를 판별하고, @for나 @each 반복문을 통해 .mt-1부터 .mt-10까지의 유틸리티 클래스를 단 3줄의 코드로 자동으로 생성해낼 수 있습니다.
| 제어문 | 자바스크립트 비교 | 사용 목적 |
|---|---|---|
| @if / @else | if () {} else {} |
테마(Light/Dark)나 조건에 따라 다른 스타일 분기 |
| @for | for (let i=1; i<=10; i++) |
1부터 N까지 순차적으로 증가하며 클래스 생성 (예: 그리드 시스템) |
| @each | array.forEach() |
컬러 리스트나 아이콘 목록 등 배열 데이터를 순회하며 생성 |
<!-- 생성된 유틸리티 클래스를 HTML에서 바로 사용 -->
<div class="mb-3 text-primary">마진 바텀 24px, 프라이머리 색상입니다.</div>
<div class="p-5 text-danger">패딩 40px, 위험 색상입니다.</div>
/* SCSS @for 및 @each 반복문 예시 */
/*
// 1. @for: 숫자를 반복하여 Margin, Padding 클래스 생성
// $i가 1부터 5까지 반복됩니다.
@for $i from 1 through 5 {
.mt-#{$i} { margin-top: #{$i * 8}px; }
.mb-#{$i} { margin-bottom: #{$i * 8}px; }
.p-#{$i} { padding: #{$i * 8}px; }
}
// 2. @each: 맵(Map, 자바스크립트의 객체와 유사) 순회하며 색상 클래스 생성
$theme-colors: (
"primary": #0d6efd,
"success": #198754,
"danger": #dc3545
);
@each $name, $color in $theme-colors {
// $name은 키(primary 등), $color는 값(#0d6efd 등)
.text-#{$name} {
color: $color;
}
.bg-#{$name} {
background-color: $color;
}
}
*/
/* 컴파일된 실제 CSS (자동으로 대량 생성됨!) */
.mt-1 { margin-top: 8px; }
.mb-1 { margin-bottom: 8px; }
.p-1 { padding: 8px; }
.mt-2 { margin-top: 16px; }
.mb-2 { margin-bottom: 16px; }
.p-2 { padding: 16px; }
/* ... (3, 4 생략) ... */
.mt-5 { margin-top: 40px; }
.mb-5 { margin-bottom: 40px; }
.p-5 { padding: 40px; }
.text-primary { color: #0d6efd; }
.bg-primary { background-color: #0d6efd; }
.text-success { color: #198754; }
.bg-success { background-color: #198754; }
.text-danger { color: #dc3545; }
.bg-danger { background-color: #dc3545; }
믹스인(@mixin)이 CSS 스타일 블록 전체를 반환한다면, 함수(@function)는 계산된 단일 값(Value)만을 반환하는 도구입니다.
픽셀(px) 단위를 상대 단위인 리단위(rem)로 변환해주는 계산식이나, 특정 공식에 따른 복잡한 애니메이션 타이밍 값을 구할 때 @function을 정의하여 사용하면 코드가 훨씬 깨끗해지고 휴먼 에러를 방지할 수 있습니다.
- @mixin: display: flex; justify-content: center; 와 같이 CSS 속성과 값의 집합을 출력할 때 사용 (반드시 @include로 호출)
- @function: 1.5rem, #ff0000 과 같이 계산된 단일 값을 출력할 때 사용 (반드시 @return 포함)
<h1 class="main-title">rem 단위 자동 변환</h1>
<p class="desc-text">픽셀 값만 넣으면 알아서 rem으로 바꿔줍니다.</p>
/* SCSS 커스텀 함수(Function) 예시 */
/*
// 1. px을 rem으로 변환하는 함수 정의
@function rem($pxValue, $baseValue: 16) {
// 수학적 연산을 통해 계산 후 @return 으로 반환
// $pxValue를 $baseValue로 나누고 'rem' 문자를 붙임 (단위 제거 기법 사용)
// SCSS 내장 모듈인 math를 사용할 수도 있습니다.
@return ($pxValue / $baseValue) * 1rem;
}
// 2. 함수 사용하기
.main-title {
// 32px을 원할 때 직관적으로 입력!
font-size: rem(32);
margin-bottom: rem(24);
}
.desc-text {
font-size: rem(18);
line-height: rem(28);
}
*/
/* 컴파일된 실제 CSS */
.main-title {
font-size: 2rem; /* 32 / 16 = 2 */
margin-bottom: 1.5rem; /* 24 / 16 = 1.5 */
}
.desc-text {
font-size: 1.125rem; /* 18 / 16 = 1.125 */
line-height: 1.75rem; /* 28 / 16 = 1.75 */
}