Sass 변수: 값을 이름으로 재사용하기

Sass 변수: 값을 이름으로 재사용하기

Sass 변수는 아주 단순해요. $로 시작하는 이름에 값을 담아 두고, 그 값을 직접 쓰는 대신 이름으로 참조하는 거예요. 단순하지만 Sass가 주는 도구 중 가장 유용한 것 중 하나입니다. 반복을 줄이고, 복잡한 계산을 하고, 라이브러리를 설정하는 데까지 쓸 수 있어요.

출처: Sass: Variables (공식 문서)

변수 선언과 사용

변수 선언은 속성 선언과 비슷하게 <변수>: <표현식> 형태로 써요. 속성은 스타일 규칙이나 at-rule 안에서만 선언할 수 있지만, 변수는 원하는 어디서든 선언할 수 있어요. 값을 쓸 자리에 변수를 넣으면 됩니다.

$base-color: #c6538c;
$border-dark: rgba($base-color, 0.88);

.alert {
  border: 1px solid $border-dark;
}

이렇게 컴파일돼요.

.alert {
  border: 1px solid rgba(198, 83, 140, 0.88);
}

Sass 변수를 헷갈리지 않으려면 조심할 게 하나 있어요. CSS에도 자체 변수(커스텀 프로퍼티)가 있는데, 이 둘은 완전히 달라요.

  • Sass 변수는 컴파일되면서 모두 사라져요. CSS 변수는 컴파일된 CSS 출력에 그대로 남습니다.
  • CSS 변수는 요소마다 값을 다르게 가질 수 있지만, Sass 변수는 한 번에 하나의 값만 가져요.
  • Sass 변수는 *명령형(imperative)*이라, 변수를 쓰고 나서 값을 바꾸면 앞서 쓴 곳은 그대로예요. CSS 변수는 *선언형(declarative)*이라 값을 바꾸면 앞선 사용에도 뒤의 사용에도 함께 영향을 줍니다.
$variable: value 1;
.rule-1 {
  value: $variable;
}

$variable: value 2;
.rule-2 {
  value: $variable;
}
.rule-1 {
  value: value 1;
}

.rule-2 {
  value: value 2;
}

한 가지 재미있는 점은, Sass 식별자는 하이픈(-)과 밑줄(_)을 똑같이 취급한다는 거예요. 그래서 $font-size$font_size는 같은 변수를 가리킵니다. Sass 초창기에 밑줄만 허용하던 때의 흔적이에요. 나중에 CSS 문법에 맞추려 하이픈을 지원하면서, 마이그레이션을 쉽게 하기 위해 둘을 동등하게 만든 겁니다.

기본값 (!default)

보통 어떤 변수에 값을 할당하면, 이미 값이 있으면 그 값을 덮어써요. 그런데 Sass 라이브러리를 만들 때는, 사용자가 CSS를 생성하기 전에 라이브러리 변수를 먼저 설정하게 하고 싶을 수 있어요. Sass는 이를 위해 !default 플래그를 제공합니다. 이 플래그는 변수가 정의되지 않았거나 값이 null일 때에만 값을 할당하고, 그 외에는 기존 값을 사용해요.

모듈 설정하기

!default로 정의한 변수는 @use 규칙으로 모듈을 불러올 때 설정할 수 있어요. 설정과 함께 불러오려면 @use <url> with (<변수>: <값>, ...) 형태로 쓰면 됩니다. 설정된 값이 변수의 기본값을 덮어써요. 설정할 수 있는 변수는 스타일시트 최상위에서 !default 플래그로 선언된 것뿐입니다.

// _library.scss
$black: #000 !default;
$border-radius: 0.25rem !default;
$box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default;

code {
  border-radius: $border-radius;
  box-shadow: $box-shadow;
}
// style.scss
@use 'library' with (
  $black: #222,
  $border-radius: 0.1rem
);
code {
  border-radius: 0.1rem;
  box-shadow: 0 0.5rem 1rem rgba(34, 34, 34, 0.15);
}

내장 변수

내장 모듈이 정의하는 변수는 수정할 수 없어요. 할당을 시도하면 실패합니다.

@use "sass:math" as math;

// This assignment will fail.
math.$pi: 0;

스코프(Scope)

스타일시트 최상위에서 선언한 변수는 *전역(global)*이에요. 자신의 모듈 안에서는 선언된 뒤 어디서든 접근할 수 있습니다. 하지만 그렇지 않은 변수도 있어요. 중괄호(SCSS)나 들여쓰기(Sass)로 묶인 블록 안에서 선언한 변수는 보통 *지역(local)*이어서, 그 블록 안에서만 접근할 수 있어요.

$global-variable: global value;

.content {
  $local-variable: local value;
  global: $global-variable;
  local: $local-variable;
}

.sidebar {
  global: $global-variable;

  // This would fail, because $local-variable isn't in scope:
  // local: $local-variable;
}
.content {
  global: global value;
  local: local value;
}

.sidebar {
  global: global value;
}

그림자(shadowing)

지역 변수는 전역 변수와 같은 이름으로 선언할 수도 있어요. 이 경우 실제로는 같은 이름의 서로 다른 변수 두 개(지역 하나, 전역 하나)가 존재해요. 이렇게 하면 지역 변수를 쓰는 작성자가 모르는 사이에 전역 변수의 값을 건드리지 않게 됩니다.

$variable: global value;

.content {
  $variable: local value;
  value: $variable;
}

.sidebar {
  value: $variable;
}
.content {
  value: local value;
}

.sidebar {
  value: global value;
}

지역 스코프(예: 믹스인 안)에서 전역 변수의 값을 바꿔야 한다면 !global 플래그를 써요. !global로 선언된 변수 할당은 항상 전역 스코프에 적용됩니다.

$variable: first global value;

.content {
  $variable: second global value !global;
  value: $variable;
}

.sidebar {
  value: $variable;
}
.content {
  value: second global value;
}

.sidebar {
  value: second global value;
}

주의할 점은, 최신 Sass(2.0.0부터)에서는 !global이 아직 선언되지 않은 변수에 쓰이면 안 된다는 거예요. !global은 파일 최상위에 이미 선언된 변수를 설정하는 데만 쓸 수 있고, 새 변수를 선언하는 데는 못 씁니다.

흐름 제어 스코프

흐름 제어 규칙 안에서 선언한 변수는 특별한 스코프 규칙을 가져요. 흐름 제어 규칙과 같은 위치에 있는 변수를 가리지 않고, 그 변수에 그대로 할당합니다. 덕분에 조건에 따라 변수에 값을 넣거나, 반복문에서 값을 쌓아올리기가 훨씬 쉬워져요.

$dark-theme: true !default;
$primary-color: #f8bbd0 !default;
$accent-color: #6a1b9a !default;

@if $dark-theme {
  $primary-color: darken($primary-color, 60%);
  $accent-color: lighten($accent-color, 60%);
}

.button {
  background-color: $primary-color;
  border: 1px solid $accent-color;
  border-radius: 3px;
}

다만 흐름 제어 스코프 안에서 새로 선언한 변수는 바깥 스코프에서 접근할 수 없어요. 즉, 흐름 제어 스코프에서 어떤 변수에 할당하려면 그 변수를 미리 선언해 두어야 합니다. 필요하다면 null로라도요.

변수용 고급 함수

Sass 핵심 라이브러리는 변수를 다루는 고급 함수 몇 개를 제공해요. meta.variable-exists() 함수는 주어진 이름의 변수가 현재 스코프에 존재하는지 돌려주고, meta.global-variable-exists()는 전역 스코프에 대해서만 같은 일을 해요.

간혹 다른 변수를 바탕으로 변수 이름을 만드는 보간(interpolation)을 쓰고 싶어 하는 분들이 있어요. Sass는 다른 변수가 어디서 정의됐는지 한눈에 알기 어려워지기 때문에 이것을 허용하지 않습니다. 대신 이름을 값으로 가진 맵(map)을 정의하고, 그 맵을 변수로 접근하면 돼요.

@use "sass:map";

$theme-colors: (
  "success": #28a745,
  "info": #17a2b8,
  "warning": #ffc107,
);

.alert {
  // Instead of $theme-color-#{warning}
  background-color: map.get($theme-colors, "warning");
}
.alert {
  background-color: #ffc107;
}

더 알아보기