CSS 변수 - 중요한 이유

CSS 변수(더 정확하게는 CSS 사용자설정 속성)가 Chrome 49에 도입됩니다. CSS의 반복을 줄이는 데 유용하며 테마 전환, 향후 CSS 기능의 확장/폴리필과 같은 강력한 런타임 효과에도 유용합니다.

CSS 혼잡성

애플리케이션을 설계할 때는 앱의 디자인을 일관되게 유지하기 위해 재사용할 브랜드 색상 집합을 따로 보관하는 것이 일반적입니다. 안타깝게도 CSS에서 이러한 색상 값을 반복해서 반복하는 것은 까다로울 뿐 아니라 오류가 발생하기도 쉽습니다. 특정 시점에 색상 중 하나를 변경해야 하는 경우 주의를 기울이고 모든 것을 '찾고 바꾸기'할 수 있지만 프로젝트가 충분히 크면 쉽게 위험해질 수 있습니다.

최근 많은 개발자가 전처리기 변수를 사용하여 이 문제를 해결하는 SASS 또는 LESS와 같은 CSS 전처리기를 사용하고 있습니다. 이러한 도구는 개발자 생산성을 크게 향상시켰지만 사용하는 변수에는 정적이며 런타임에 변경할 수 없다는 큰 단점이 있습니다. 런타임에 변수를 변경할 수 있는 기능을 추가하면 동적 애플리케이션 테마 설정과 같은 기능을 사용할 수 있을 뿐만 아니라 반응형 디자인 및 향후 CSS 기능에 폴리필할 가능성도 크게 향상됩니다. Chrome 49 출시와 함께 이러한 기능을 CSS 사용자 지정 속성의 형태로 사용할 수 있게 되었습니다.

커스텀 속성 요약

맞춤 속성은 CSS 도구 상자에 두 가지 새로운 기능을 추가합니다.

  • 작성자가 작성자가 선택한 이름으로 속성에 임의의 값을 할당할 수 있는 기능입니다.
  • var() 함수: 작성자가 다른 속성에서 이러한 값을 사용할 수 있습니다.

다음은 이를 보여주는 간단한 예시입니다.

:root {
    --main-color: #06c;
}

#foo h1 {
    color: var(--main-color);
}

--main-color는 값이 #06c인 작성자가 정의한 맞춤 속성입니다. 모든 커스텀 속성은 대시 2개로 시작합니다.

var() 함수는 자체를 검색하여 맞춤 속성 값으로 바꾸므로 color: #06c;가 됩니다. 맞춤 속성이 스타일시트의 어딘가에 정의되어 있는 한 var 함수에서 사용할 수 있습니다.

처음에는 구문이 약간 이상해 보일 수 있습니다. 많은 개발자가 '변수 이름에 $foo을 사용하면 안 되나요?'라고 묻습니다. 이 접근 방식은 특히 최대한 유연하고 향후 $foo 매크로를 허용할 수 있도록 선택되었습니다. 배경에 관한 자세한 내용은 사양 작성자 중 한 명인 탭 애킨스의 이 게시물을 참고하세요.

커스텀 속성 문법

맞춤 속성의 문법은 간단합니다.

--header-color: #06c;

맞춤 속성은 대소문자를 구분하므로 --header-color--Header-Color는 서로 다른 맞춤 속성입니다. 단순해 보이지만 맞춤 속성에 허용되는 문법은 실제로 매우 관대합니다. 예를 들어 다음은 유효한 커스텀 속성입니다.

--foo: if(x > 5) this.width = 10;

일반 속성에서는 유효하지 않기 때문에 변수로 유용하지는 않지만, 런타임에 JavaScript로 읽고 처리할 수 있습니다. 즉, 맞춤 속성을 사용하면 현재 CSS 전처리기로는 불가능한 모든 종류의 흥미로운 기술을 활용할 수 있습니다. '하품이 있는데도 짜증 나는 사람이 있다고 생각한다면 한 번 더 보세요. 이러한 변수는 이전에 사용하던 변수가 아닙니다.

폭포

맞춤 속성은 표준 캐스케이드 규칙을 따르므로 다양한 수준의 구체성으로 동일한 속성을 정의할 수 있습니다.

:root { --color: blue; }
div { --color: green; }
#alert { --color: red; }
* { color: var(--color); }
<p>I inherited blue from the root element!</p>
<div>I got green set directly on me!</div>
<div id="alert">
    While I got red set directly on me!
    <p>I’m red too, because of inheritance!</p>
</div>

즉, 미디어 쿼리 내에서 맞춤 속성을 활용하여 반응형 디자인을 지원할 수 있습니다. 한 가지 사용 사례는 화면 크기가 커짐에 따라 주요 섹션 지정 요소 주변의 여백을 확장하는 것입니다.

:root {
    --gutter: 4px;
}

section {
    margin: var(--gutter);
}

@media (min-width: 600px) {
    :root {
    --gutter: 16px;
    }
}

미디어 쿼리 내부에서 변수를 정의할 수 없는 현재의 CSS 전처리기로는 위의 코드 스니펫을 사용할 수 없다는 점에 유의해야 합니다. 이 기능을 사용하면 많은 잠재력을 발휘할 수 있습니다.

다른 맞춤 속성에서 값을 가져오는 맞춤 속성을 보유할 수도 있습니다. 이는 테마 설정에 매우 유용할 수 있습니다.

:root {
    --primary-color: red;
    --logo-text: var(--primary-color);
}

var() 함수

맞춤 속성의 값을 검색하고 사용하려면 var() 함수를 사용해야 합니다. var() 함수의 문법은 다음과 같습니다.

var(<custom-property-name> [, <declaration-value> ]? )

여기서 <custom-property-name>--foo와 같은 작성자 정의 맞춤 속성의 이름이고 <declaration-value>는 참조된 맞춤 속성이 잘못된 경우 사용할 대체 값입니다. 대체 값은 쉼표로 구분된 목록일 수 있으며, 이 목록은 단일 값으로 결합됩니다. 예를 들어 var(--font-stack, "Roboto", "Helvetica");"Roboto", "Helvetica"의 대체를 정의합니다. 마진 및 패딩에 사용되는 것과 같은 축약된 값은 쉼표로 구분되지 않으므로 패딩에 적절한 대체 값은 다음과 같습니다.

p {
    padding: var(--pad, 10px 15px 20px);
}

구성요소 작성자는 이러한 대체 값을 사용하여 요소의 방어 스타일을 작성할 수 있습니다.

/* In the component’s style: */
.component .header {
    color: var(--header-color, blue);
}
.component .text {
    color: var(--text-color, black);
}

/* In the larger application’s style: */
.component {
    --text-color: #080;
    /* header-color isn’t set,
        and so remains blue,
        the fallback value */
}

맞춤 속성은 그림자 경계를 통과할 수 있으므로 이 기법은 Shadow DOM을 사용하는 웹 구성요소의 테마를 설정하는 데 특히 유용합니다. 웹 구성요소 작성자는 대체 값을 사용하여 초기 디자인을 만들고 테마 설정 '후크'를 맞춤 속성 형식으로 노출할 수 있습니다.

<!-- In the web component's definition: -->
<x-foo>
    #shadow
    <style>
        p {
        background-color: var(--text-background, blue);
        }
    </style>
    <p>
        This text has a yellow background because the document styled me! Otherwise it
        would be blue.
    </p>
</x-foo>
/* In the larger application's style: */
x-foo {
    --text-background: yellow;
}

var()를 사용할 때는 주의해야 할 몇 가지 사항이 있습니다. 변수는 속성 이름이 될 수 없습니다. 예를 들면 다음과 같습니다.

.foo {
    --side: margin-top;
    var(--side): 20px;
}

하지만 이는 margin-top: 20px; 설정과는 다릅니다. 대신 두 번째 선언은 유효하지 않으며 오류로 발생합니다.

마찬가지로 값의 일부가 변수에 의해 제공되는 값을 단순히 빌드할 수는 없습니다.

.foo {
    --gap: 20;
    margin-top: var(--gap)px;
}

다시 한번 말씀드리지만, 이는 margin-top: 20px;를 설정하는 것과는 다릅니다. 값을 빌드하려면 calc() 함수가 필요합니다.

calc()를 사용하여 값 빌드

이전에 사용해 본 적이 없다면 calc() 함수는 계산을 실행하여 CSS 값을 결정할 수 있는 편리한 도구입니다. 모든 최신 브라우저에서 지원되며 맞춤 속성과 결합하여 새 값을 만들 수 있습니다. 예를 들면 다음과 같습니다.

.foo {
    --gap: 20;
    margin-top: calc(var(--gap) * 1px); /* niiiiice */
}

JavaScript에서 맞춤 속성 작업하기

런타임 시 맞춤 속성의 값을 가져오려면 계산된 CSSStyleDeclaration 객체의 getPropertyValue() 메서드를 사용합니다.

/* CSS */
:root {
    --primary-color: red;
}

p {
    color: var(--primary-color);
}
<!-- HTML -->
<p>I’m a red paragraph!</p>
/* JS */
var styles = getComputedStyle(document.documentElement);
var value = String(styles.getPropertyValue('--primary-color')).trim();
// value = 'red'

마찬가지로 런타임 시 맞춤 속성 값을 설정하려면 CSSStyleDeclaration 객체의 setProperty() 메서드를 사용합니다.

/* CSS */
:root {
    --primary-color: red;
}

p {
    color: var(--primary-color);
}
<!-- HTML -->
<p>Now I’m a green paragraph!</p>
/* JS */
document.documentElement.style.setProperty('--primary-color', 'green');

setProperty() 호출에서 var() 함수를 사용하여 런타임 시 다른 커스텀 속성을 참조하도록 커스텀 속성의 값을 설정할 수도 있습니다.

/* CSS */
:root {
    --primary-color: red;
    --secondary-color: blue;
}
<!-- HTML -->
<p>Sweet! I’m a blue paragraph!</p>
/* JS */
document.documentElement.style.setProperty('--primary-color', 'var(--secondary-color)');

맞춤 속성은 스타일시트의 다른 맞춤 속성을 참조할 수 있으므로 이를 통해 다양한 종류의 흥미로운 런타임 효과를 얻을 수 있습니다.

브라우저 지원

현재 Chrome 49, Firefox 42, Safari 9.1, iOS Safari 9.3에서는 맞춤 속성을 지원합니다.

데모

샘플에서 커스텀 속성 덕분에 활용할 수 있는 흥미로운 기법을 모두 살펴보세요.

추가 자료

맞춤 속성에 대해 자세히 알아보려면 Google 애널리틱스팀의 필립 월튼이 작성한 맞춤 속성에 기대하는 이유에 관한 기본 정보를 참고하세요. 다른 브라우저의 진행 상황은 chromestatus.com에서 확인할 수 있습니다.