CSS 전처리기 (Sass) 입문
SCSS의 변수·중첩·믹스인·extend·모듈(@use/@forward)을 사용하고 컴파일 결과가 표준 CSS가 되는 흐름을 익힙니다.
지금까지는 순수 CSS만으로 페이지를 꾸미고, CSS 변수와 calc() 같은 기능으로 코드를 정리했습니다. 요즘의 CSS에는 이런 기능에 더해 선택자를 중첩해 쓰는 표준 중첩 문법까지 생겨 표현력이 크게 늘었습니다. 그래도 프로젝트가 커지면 반복되는 선언 묶음, 빌드할 때 미리 계산할 값, 여러 파일에서 나눠 쓰는 규칙을 일관되게 관리해야 할 때가 있습니다. 이때 쓰는 도구가 CSS 전처리기(preprocessor)입니다.
대표적인 전처리기에는 Sass(Syntactically Awesome Style Sheets), Less, Stylus가 있습니다. 이 글에서는 가장 널리 쓰이는 Sass를, 표준 CSS와 가장 비슷한 문법인 SCSS(Sassy CSS)로 다룹니다. Sass는 CSS와 호환되는 문법에 변수, 믹스인, 함수, 모듈 같은 기능을 더한 스타일 시트 언어이며, 작성한 SCSS는 Dart Sass 컴파일러를 거쳐 브라우저가 읽는 표준 CSS가 됩니다. 브라우저는 SCSS를 직접 읽지 않고, 컴파일한 CSS만 해석합니다.
SASS · BUILD TIME
브라우저는 SCSS가 아니라 컴파일된 CSS를 읽는다
Dart Sass가 SCSS의 변수·mixin·module을 CSS로 변환한다. 브라우저의 cascade와 렌더링은 생성된 CSS를 불러온 뒤 수행된다.
빌드 시점 값과 런타임 값의 역할을 나눈다
Sass 변수와 mixin은 빌드 시점에 평가된다. 출력 CSS에 남은 custom property와 media query는 브라우저에서 cascade·상속·화면 조건에 따라 적용된다.
sass와 --watch의 책임은 SCSS를 CSS로 변환하는 데까지다. 파일 bundling과 asset URL 처리는 별도 build tool의 책임이다.
위 그림은 SCSS 파일이 화면에 그려지기까지의 네 단계를 보여 줍니다. 변수, 믹스인, @use를 쓴 .scss 파일을 Dart Sass가 컴파일하면 표준 선택자와 값만 남은 .css 파일이 만들어지고, 브라우저는 이 CSS를 불러와 cascade를 거쳐 화면을 그립니다. --watch는 파일을 저장할 때마다 같은 컴파일을 다시 할 뿐, 브라우저를 새로고침하거나 여러 파일을 하나로 묶는 번들링을 대신하지는 않습니다.
그림 아래의 설명처럼 Sass 변수와 믹스인은 빌드할 때 계산되어 사라지고, 출력된 CSS에 남은 CSS 변수와 미디어 쿼리는 브라우저에서 cascade, 상속, 화면 조건에 따라 적용됩니다. 무엇이 빌드할 때 정해지고 무엇이 브라우저에서 정해지는지 구분하는 것이 Sass를 쓰는 출발점입니다.
전처리기가 필요한 이유
CSS 전처리기는 CSS를 확장한 언어입니다. 개발자가 전처리기의 문법으로 코드를 쓰면, 전처리기가 이를 일반 CSS로 바꿔(컴파일해) 줍니다. Sass는 다음 기능을 제공합니다.
- 변수: 반복되는 값에 이름을 붙이고, 빌드할 때의 계산이나 모듈 설정에 씁니다. 컴파일한 CSS에서는 실제 값으로 바뀝니다.
- 중첩: 관련된 선택자를 가까이 모아 쓰고, 부모 선택자
&로 상태나 가상 요소를 붙입니다. - 믹스인: 자주 반복되는 선언 묶음을 함수처럼 정의해 필요한 곳에 넣습니다.
- 확장: 같은 의미의 선택자들이 한 규칙을 함께 쓰게 해, 선언의 중복을 줄입니다.
- 부분 파일과 모듈: 다시 쓸 코드를 부분 파일(partial)로 나누고,
@use로 이름 공간(namespace)이 있는 모듈로 불러오며,@forward로 여러 모듈을 한 진입점에서 내보냅니다. - 계산과 함수:
sass:math,sass:color같은 내장 모듈로 숫자와 색을 빌드할 때 계산합니다.
Sass 설치와 컴파일
Sass의 주 구현체는 Dart Sass이며, 이 교재는 Sass 팀이 npm에 배포하는 sass 패키지를 씁니다. 이 패키지는 Dart Sass를 자바스크립트로 옮긴 구현과 명령줄 도구를 함께 제공합니다. 예전에 쓰던 Ruby Sass, Node Sass, LibSass는 유지 보수가 끝났으므로 새 프로젝트에서는 쓰지 않습니다.
Node.js와 npm이 필요합니다. 터미널에서 node -v와 npm -v를 입력해 버전이 보이는지 확인하고, 보이지 않으면 Node.js 공식 사이트에서 설치합니다. 그다음 프로젝트 폴더를 만들어 이동하고, npm 프로젝트를 초기화합니다.
mkdir my-sass-project
cd my-sass-projectnpm init -ynpm init -y는 기본값으로 package.json 파일을 만듭니다. 이어서 Sass를 이 프로젝트의 개발 의존성으로 설치합니다.
npm install --save-dev sass # 프로젝트 내 설치 (프로젝트에서만 사용)
npx sass --version프로젝트에 설치하면 이 프로젝트가 쓰는 Sass의 버전이 package.json과 lockfile에 기록되어, 다른 사람도 같은 버전으로 컴파일할 수 있습니다. 이 글을 쓰는 시점의 최신 버전은 1.107이며, 이후 예제는 프로젝트에 설치한 실행 파일을 npx sass로 실행합니다.
SCSS 파일(*.scss)을 CSS 파일(*.css)로 컴파일하는 기본 명령은 다음과 같습니다.
npx sass input.scss output.css개발 중에는 저장할 때마다 다시 컴파일하는 감시(watch) 모드가 편합니다. 입력:출력 형태로 파일을 지정합니다.
npx sass --watch input.scss:output.css
# 예시: npx sass --watch scss/main.scss:css/style.css이 명령을 실행하면 터미널이 계속 기다리면서, input.scss가 바뀔 때마다 output.css를 다시 만듭니다. 감시를 끝내려면 그 터미널에서 Ctrl + C를 누릅니다.
Sass의 핵심 기능
SASS · BUILD TIME
Sass 기능은 컴파일 결과를 보고 선택한다
반복되는 값·선언·선택자 관계에 맞는 기능을 고른다. 생성되는 CSS의 중복, selector와 module API를 함께 확인한다.
| 기능 | 선택할 때 | 확인할 점 |
|---|---|---|
| 변수 | 반복되는 빌드 시점 값, 계산, 모듈 설정에 이름을 붙일 때 | $variable은 값으로 치환되어 사라진다. 런타임 테마에는 CSS custom property를 쓴다. |
| 중첩 | 관련 선택자와 & 상태를 가까이 둘 때 |
얕게 유지하고 생성된 선택자의 길이와 specificity를 확인한다. |
@mixin |
인자를 받는 의미 있는 선언 묶음이 반복될 때 | @include 위치마다 선언이 출력되므로 한 값의 별칭으로 남용하지 않는다. |
@extend |
같은 의미의 선택자들이 하나의 규칙을 공유할 때 | 선택자 목록이 확장된다. placeholder는 확장될 때만 출력된다. |
| partial + module | 파일을 나누고 소비자에게 공개할 API를 정할 때 | @use namespace와 @forward 진입점을 사용한다. |
| 계산 · 함수 | 숫자나 색상을 빌드 시점에 변환할 때 | math.div(), color.adjust(…, $space: hsl)처럼 module API를 명시한다. |
- 변수
- 선택 반복되는 빌드 시점 값, 계산, 모듈 설정
- 확인
$variable은 사라진다. 런타임 테마는 CSS custom property로 둔다. - 중첩
- 선택 관련 선택자와
&상태를 가까이 둘 때 - 확인 얕게 유지하고 생성된 선택자와 specificity를 본다.
@mixin- 선택 인자를 받는 의미 있는 선언 묶음이 반복될 때
- 확인
@include위치마다 선언이 출력된다. @extend- 선택 같은 의미의 선택자가 규칙을 공유할 때
- 확인 선택자 목록이 확장되고 placeholder는 사용될 때만 출력된다.
- partial + module
- 선택 파일을 나누고 공개 API를 정할 때
- 확인
@usenamespace와@forward진입점을 쓴다. - 계산 · 함수
- 선택 숫자와 색상을 빌드 시점에 변환할 때
- 확인
math.div()와sass:colormodule API를 쓴다.
선언 복사와 선택자 확장은 다른 결과를 만든다
@include는 호출 지점에 mixin의 내용을 출력하고, @extend는 관련 선택자 규칙을 확장한다. 브라우저 테마와 요소별 값은 CSS custom property 등 표준 CSS로 설계한다.
Sass 기능은 빌드 시점에 평가된다. 브라우저 런타임의 테마, cascade, 요소별 값은 표준 CSS 기능으로 설계한다.
위 그림은 해결하려는 문제에 따라 Sass 기능을 고르는 기준을 보여 줍니다. 반복되는 값에는 변수를 쓰면 출력에 실제 값이 들어가고, 인자(argument, 인수라고도 합니다)를 받는 선언 묶음에는 @mixin과 @include를 쓰면 호출한 위치마다 선언이 출력되며, 같은 의미의 규칙에는 @extend를 쓰면 선택자 목록을 함께 씁니다. 세 쌍은 차례로 거치는 단계가 아니라 서로 다른 문제에 대한 답입니다.
그림 아래의 표는 중첩, 모듈, 함수까지 포함해 기능마다 확인할 점을 정리합니다. 중첩은 얕게 유지해 생성되는 선택자가 길어지지 않게 하고, 믹스인은 쓴 곳마다 선언이 복사되므로 값 하나의 별칭으로 남용하지 않으며, 계산에는 math.div()와 color.adjust() 같은 내장 모듈 함수를 씁니다. 그림 위의 문장처럼 기능의 이름보다 컴파일 결과를 보고 고릅니다.
변수
Sass 변수는 $이름: 값; 형식으로 선언합니다. 값에는 색, 길이, 글꼴 목록처럼 CSS에 쓸 수 있는 값을 그대로 적습니다. 다음 코드는 위쪽에서 변수 네 개를 선언하고, 아래 body와 .button 규칙의 값 자리에서 그 이름을 씁니다.
/* style.scss */
$primary-color: #3498db;
$text-color: #333;
$font-stack: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
$base-padding: 15px;
body {
font-family: $font-stack;
color: $text-color;
background-color: #f0f2f5;
}
.button {
background-color: $primary-color;
padding: $base-padding;
color: white;
border: none;
border-radius: 5px;
}컴파일하면 $primary-color 같은 변수는 모두 #3498db 같은 실제 값으로 바뀌어, 출력된 CSS에는 Sass 변수가 남지 않습니다. 반면 CSS 변수는 출력된 CSS에 그대로 남아 브라우저에서 cascade와 상속을 거치고, 요소마다 다른 값을 가질 수 있습니다. 그래서 빌드할 때 정해지는 상수, 계산, 모듈 설정에는 Sass 변수를, 브라우저에서 바뀌는 테마나 요소마다 다른 값에는 CSS 변수를 씁니다.
중첩
중첩을 쓰면 관련된 선택자를 부모 선택자 안에 모아 쓸 수 있습니다. 다음 코드처럼 규칙 안에 다른 규칙을 쓰면, 컴파일할 때 안쪽 선택자 앞에 바깥 선택자가 공백과 함께 붙어 자손 선택자가 됩니다.
/* SCSS */
.site-nav {
ul {
margin: 0;
padding: 0;
list-style: none;
}
li {
display: inline-block;
margin-right: 10px;
}
a {
display: inline-block;
padding: 8px 12px;
text-decoration: none;
color: #333;
&:hover { /* 부모 선택자(&) */
background-color: lightgray;
}
}
}컴파일하면 다음 CSS가 됩니다. 중첩은 Sass 파일 안에서만 쓰는 표기이므로, 브라우저가 받는 CSS에는 .site-nav ul처럼 풀어 쓴 선택자만 남습니다. 출력된 네 규칙이 SCSS의 어느 블록에서 나왔는지 비교해 보세요.
/* CSS */
.site-nav ul {
margin: 0;
padding: 0;
list-style: none;
}
.site-nav li {
display: inline-block;
margin-right: 10px;
}
.site-nav a {
display: inline-block;
padding: 8px 12px;
text-decoration: none;
color: #333;
}
.site-nav a:hover {
background-color: lightgray;
}&는 중첩된 규칙에서 부모 선택자를 가리키므로, &:hover는 .site-nav a:hover가 됩니다. :hover나 ::before 같은 상태와 가상 요소를 붙일 때 씁니다. 중첩은 HTML의 계층을 그대로 따라 깊게 쓰기 쉬운데, 그러면 생성되는 선택자가 길어지고 명시도가 높아집니다. 보통 한두 단계로 제한하고, 컴파일한 선택자를 함께 확인합니다. 표준 CSS의 중첩 문법도 비슷하게 생겼지만, 선택자 목록의 명시도 같은 일부 동작이 Sass의 결과와 다를 수 있습니다.
더 깊이: 표준 CSS 중첩과 Sass 중첩은 어디서 갈라질까
브라우저가 직접 읽는 표준 CSS 중첩은 2023년 12월부터 주요 브라우저에서 함께 쓸 수 있게 되었습니다. 겉모습은 Sass와 비슷하지만, Sass는 컴파일할 때 부모 선택자를 안쪽 선택자와 합쳐 새 선택자를 써 내는 반면, 표준 중첩은 브라우저가 안쪽 선택자를 부모에 대한 관계로 해석한다는 점이 다릅니다. 이 차이 때문에 같은 코드가 다른 결과를 냅니다.
첫째는 이어 붙이기입니다. Sass에서 .card { &__title { ... } }는 .card__title이 되어 BEM의 요소 이름을 만드는 데 자주 쓰이지만, 표준 중첩에서는 &에 글자를 이어 붙여 새 클래스 이름을 만들 수 없습니다. 그래서 BEM 이름을 중첩으로 만드는 코드는 Sass를 거쳐야만 의도대로 동작합니다.
둘째는 명시도입니다. Sass는 #a, b { & c { ... } }를 #a c, b c처럼 부모 목록의 항목마다 따로 적은 선택자로 펼치므로, b c로 맞은 요소는 0-0-2의 명시도를 가집니다. 표준 중첩은 안쪽 규칙을 :is(#a, b) c처럼 다루고, :is()는 괄호 안에서 가장 높은 명시도를 가져오므로 b로 맞은 요소도 1-0-1이 됩니다. Sass로 쓰던 코드를 표준 중첩으로 옮길 때 덮어쓰기 결과가 바뀌었다면 이 차이를 먼저 의심해 봅니다. 표준 문법의 규칙은 MDN의 CSS 중첩 사용법에 정리되어 있습니다.
믹스인
함께 반복되는 선언 묶음은 @mixin으로 정의하고 @include로 넣습니다. 인자를 받으면 같은 묶음에서 필요한 값만 바꿔 쓸 수 있고, 인자에는 $gap: 12px처럼 기본값을 줄 수 있습니다.
/* SCSS */
@mixin cluster($gap: 12px) {
display: flex;
align-items: center;
justify-content: center;
gap: $gap;
}
@mixin surface($padding: 16px, $radius: 8px) {
padding: $padding;
border: 1px solid #d9d9d9;
border-radius: $radius;
}
.toolbar {
@include cluster(16px);
}
.card {
@include surface(20px, 8px);
background-color: white;
}.toolbar는 $gap에 16px을 넘겼고, .card는 두 인자를 모두 넘겼습니다. $radius에 넘긴 8px은 기본값과 같으므로 생략해도 결과가 같습니다. 컴파일하면 다음 CSS가 되며, 믹스인의 이름은 사라지고 인자가 들어간 선언만 각 규칙 안에 복사됩니다.
/* CSS */
.toolbar {
display: flex;
align-items: center;
justify-content: center;
gap: 16px;
}
.card {
padding: 20px;
border: 1px solid #d9d9d9;
border-radius: 8px;
background-color: white;
}@include를 쓴 곳마다 선언이 복사되어 출력되므로, 믹스인은 속성 하나의 짧은 이름을 만드는 데보다 의미 있는 선언 묶음과 그 인자를 다시 쓸 때 알맞습니다. 브라우저 호환을 위한 접두사(vendor prefix)를 붙이는 일은 믹스인에 맡기지 않고, 빌드 단계의 다른 도구로 처리합니다.
확장: @extend
@extend는 다른 선택자의 규칙에 현재 선택자를 함께 붙입니다. HTML의 부모와 자식이나 CSS의 상속과는 관계없이, 대상 선택자가 쓰인 모든 규칙의 선택자 목록에 현재 선택자를 더하는 방식입니다. 같은 의미를 가진 선택자들이 규칙을 함께 쓸 때 씁니다.
/* SCSS */
.message {
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
}
.message--success {
@extend .message; /* .message가 쓰인 규칙에 현재 선택자를 추가 */
background-color: #d4edda;
color: #155724;
border-color: #c3e6cb;
}
.message--error {
@extend .message;
background-color: #f8d7da;
color: #721c24;
border-color: #f5c6cb;
}컴파일하면 다음 CSS가 됩니다. 믹스인과 달리 .message의 공통 선언은 한 번만 출력되고, 그 규칙의 선택자 목록에 .message--success와 .message--error가 더해집니다. 각 변형 클래스에서 따로 적은 색 선언은 별도의 규칙으로 남습니다.
/* CSS */
.message, .message--success, .message--error { /* 선택자들이 그룹화됨 */
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
}
.message--success {
background-color: #d4edda;
color: #155724;
border-color: #c3e6cb;
}
.message--error {
background-color: #f8d7da;
color: #721c24;
border-color: #f5c6cb;
}@extend는 플레이스홀더 선택자(%이름)와 함께 쓰면 더 깔끔합니다. 플레이스홀더는 다른 선택자가 확장할 때만 출력되므로, 공통 규칙만을 위한 쓸모없는 클래스가 CSS에 생기지 않습니다. 다음 코드를 컴파일하면 %common-button-style 대신 .btn-submit이 들어간 규칙 하나와, 색을 정한 .btn-submit 규칙이 출력됩니다.
%common-button-style {
padding: 10px 15px;
border-radius: 5px;
cursor: pointer;
}
.btn-submit {
@extend %common-button-style;
background-color: blue;
color: white;
}부분 파일과 모듈: @use, @forward
다시 쓸 코드만 담은 파일은 _variables.scss처럼 이름 앞에 밑줄을 붙인 부분 파일로 만듭니다. 폴더 전체를 컴파일할 때 Sass는 이런 파일을 따로 CSS로 만들지 않고, 다른 파일이 불러올 때만 그 내용을 씁니다. 불러올 때는 밑줄과 확장자를 생략합니다.
예전에 쓰던 Sass의 @import와 이름 공간 없이 부르는 내장 함수는 Dart Sass 1.80.0부터 사용 중단(deprecated)되어 쓰면 경고가 나오며, Dart Sass 3.0.0에서 없어질 예정입니다. 새 코드에서는 @use로 모듈을 한 번 불러와 이름 공간을 붙여 쓰고, 여러 파일의 공개할 내용을 한 진입점에서 내보낼 때는 @forward를 씁니다.
/* styles/_variables.scss */
$font-size-base: 16px;
$color-main: #3498db;
/* styles/_mixins.scss */
@mixin button-style {
padding: 10px 20px;
border-radius: 5px;
}
/* styles/_index.scss: 공개 진입점 */
@forward 'variables';
@forward 'mixins';
/* style.scss */
@use 'styles';
body {
font-size: styles.$font-size-base;
color: styles.$color-main;
}
.my-button {
@include styles.button-style;
background-color: styles.$color-main;
color: white;
}이 코드 블록은 네 파일의 내용을 한곳에 모아 보여 준 것입니다. 주석에 적힌 이름대로 styles/_variables.scss, styles/_mixins.scss, styles/_index.scss, style.scss의 네 파일로 나눠 저장하고, 프로젝트 폴더에서 npx sass style.scss style.css를 실행합니다. 한 파일에 모두 붙여 넣으면 모듈 구조를 실습한 것이 아닙니다.
_index.scss의 @forward는 사용하는 쪽에 공개할 변수와 믹스인을 모으고, @use 'styles'는 styles 폴더의 _index.scss를 불러와 그 내용을 styles.라는 이름 공간 아래에 둡니다. 컴파일한 .my-button에는 세로 10px, 가로 20px의 안쪽 여백, 5px의 모서리 반경, 파란 배경과 흰 글자가 출력되고, styles.$color-main 같은 Sass 참조는 남지 않습니다. 이름 앞에 출처가 붙으므로, 여러 모듈에 같은 이름이 있어도 충돌하지 않습니다.
계산
Sass는 숫자와 색을 빌드할 때 계산할 수 있습니다. 내장 기능은 @use 'sass:math'처럼 모듈을 불러와 이름 공간과 함께 씁니다.
/* SCSS */
@use 'sass:color';
@use 'sass:math';
$base-font-size: 16px;
$line-height: 1.5;
$margin-unit: 10px;
body {
font-size: $base-font-size;
line-height: $line-height;
}
.box {
width: 100px + 50px; /* 150px */
height: math.div(200px, 2); /* 100px */
padding: $margin-unit * 2; /* 20px */
margin: $margin-unit - 5px; /* 5px */
font-size: $base-font-size * 1.2; /* 19.2px */
}
/* 색상 연산 */
$color-primary: #3498db;
$color-darker: color.adjust($color-primary, $lightness: -10%, $space: hsl);
$color-lighter: color.adjust($color-primary, $lightness: 15%, $space: hsl);
.header {
background-color: $color-darker;
color: white;
}
.footer {
background-color: $color-lighter;
}숫자를 나눌 때는 사용 중단 예정인 / 대신 math.div()를 씁니다. CSS에서 /는 font: 16px/1.5처럼 값을 구분하는 기호로도 쓰여 헷갈리기 때문입니다. color.adjust($color-primary, $lightness: -10%, $space: hsl)은 HSL 색 공간에서 밝기만 10% 낮춘 색을 계산하며, 예전의 darken() 함수와 같은 결과를 냅니다. $color-primary의 밝기가 약 53%이므로 어두운 색은 약 43%, 밝은 색은 약 68%의 밝기가 됩니다.
정리
- Sass는 CSS를 확장한 언어이며, Dart Sass가 SCSS를 표준 CSS로 컴파일하고 브라우저는 그 CSS만 읽습니다.
sass패키지를 프로젝트에 설치하고npx sass 입력 출력으로 컴파일하며,--watch는 저장할 때마다 다시 컴파일합니다.- Sass 변수는 빌드할 때 실제 값으로 바뀌어 사라지고, CSS 변수는 출력에 남아 브라우저에서 계산됩니다.
- 중첩은 얕게 유지하고, 믹스인은 쓴 곳마다 선언이 복사되며,
@extend는 선택자 목록을 함께 쓰게 합니다. - 부분 파일은 밑줄로 시작하고,
@use로 이름 공간과 함께 불러오며,@forward로 공개할 내용을 모읍니다. - 나눗셈은
math.div()로, 색 계산은color.adjust()같은 내장 모듈 함수로 합니다.
연습 문제
1. 바뀌지 않는 버튼
변수 예제의 $base-padding을 20px로 바꿔 저장했는데, 브라우저의 버튼 여백이 그대로입니다. HTML은 올바른 style.css를 연결하고 있습니다. 먼저 무엇을 확인해야 할까요?
해설 보기
SCSS 파일이 다시 컴파일되어 style.css가 바뀌었는지부터 확인합니다. $base-padding은 컴파일할 때 값으로 바뀌므로, SCSS만 저장하고 컴파일하지 않았다면 브라우저가 읽는 CSS는 예전 값 그대로입니다. --watch를 실행하고 있었다면 그 터미널에 컴파일 오류가 출력되지 않았는지도 봅니다.
style.css에 20px이 들어간 것을 확인한 뒤에도 그대로라면, 브라우저를 새로고침해 바뀐 CSS를 다시 받아 오게 합니다.
2. 개발자 도구에서 바꾸기
출력된 CSS에 --spacing-unit: 15px라는 CSS 변수와, $base-padding에서 온 padding: 15px가 함께 있습니다. 개발자 도구에서 둘의 값을 각각 20px로 바꾸면 무엇이 달라질까요?
해설 보기
--spacing-unit을 바꾸면 그 변수를 var()로 쓰는 모든 요소가 브라우저에서 바로 다시 계산되어 함께 바뀝니다. CSS 변수는 브라우저의 cascade에 참여하기 때문입니다.
padding: 15px는 Sass 변수가 이미 값으로 바뀐 결과라, 개발자 도구에서 고치면 그 선언 하나만 바뀝니다. 같은 $base-padding에서 나온 다른 선언은 그대로이며, 브라우저는 그 값들이 같은 변수에서 왔다는 것을 모릅니다.
3. 믹스인과 확장의 출력
.alert-a와 .alert-b가 같은 선언 다섯 줄을 함께 씁니다. 이 묶음을 믹스인으로 만들어 두 선택자에 @include한 경우와, 플레이스홀더로 만들어 두 선택자에서 @extend한 경우, 출력된 CSS는 어떻게 다를까요?
해설 보기
믹스인을 쓰면 .alert-a 규칙과 .alert-b 규칙 안에 다섯 줄의 선언이 각각 복사되어, 같은 선언이 두 번 출력됩니다.
플레이스홀더를 확장하면 .alert-a, .alert-b { ... }처럼 두 선택자가 한 규칙을 함께 쓰므로 선언은 한 번만 출력됩니다. 대신 이 공통 규칙이 각 선택자의 다른 규칙과 떨어진 위치에 출력되어 소스 순서가 달라질 수 있으므로, 어느 쪽이든 컴파일한 결과를 확인하고 고릅니다.
다음 글 Sass로 반응형 블로그 헤더 만들기에서는 이 기능들로 부분 파일과 믹스인을 나눠 반응형 헤더를 직접 만들어 봅니다.