CSS Custom Properties (커스텀속성) 소개

Posted by in Research

(https://www.smashingmagazine.com/2017/04/start-using-css-custom-properties/ 문서를 토대로 번역하고, 다른 문서들을 조합해 정리하였습니다.)

1. 전처리기 변수와 CSS 커스텀 속성

오늘날 CSS 전처리기는 웹개발에서 중요한 역할을 수행하고 있습니다. (Sass, Stylus, Less, PostCSS 등)
전처리기의 주요 장점 중 하나는 변수를 사용할 수 있다는 것인데요. 변수를 사용하면 복붙을 피할 수 있고, 개발과 리팩토링이 간단해집니다.

그러나, 전처리기 변수에는 다음과 같은 몇가지 한계가 있습니다.

  • 동적으로 변경할 수 없다.
  • DOM 구조를 알지 못한다.
  • JavaScript에서 읽거나 변경할 수 없다.

이러한 문제를 해결하기 위해 CSS 커스텀 속성이 개발되었습니다. 전처리기와 CSS 커스텀 속성 두 가지가 어떤 점이 다른지는 아래에서 더 자세히 알아보도록 하겠습니다.

2. CSS 커스텀 속성

CSS 커스텀 속성은 작성자가 정의한 속성의 집합입니다. 작성자는 임의로 정한 이름의 속성에 임의의 값을 할당할 수 있습니다. “CSS 변수”라고 부르기도 하지만 올바른 이름은 “CSS 커스텀 속성”입니다. CSS 커스텀 속성은 아래와 같이 정의할 수 있습니다.

  • root{} 커스텀 속성을 전역으로 사용하고자 할 때, :root {} 에 커스텀 속성을 정의합니다.
    커스텀 속성은 CSS 변수처럼 [속성]: [값]; 의 구문을 따르기 때문에 반드시 범위(중괄호) 내에 정의되어야 합니다.
  • --var-name 커스텀 속성의 이름입니다. 이름은 --(이중 하이픈)로 시작하며, 속성 이름은 작성자가 정의합니다.
    CSS 커스텀 속성은 CSS 변수처럼 보이고 작동하며, 보통은 속성 이름에 작동 방식을 반영합니다.
    그리고 다른 CSS 속성들과는 달리 CSS 커스텀 속성은 대소문자를 구분합니다.
  • value 커스텀 속성의 값입니다. 값에는 모든 CSS 값이 들어갈 수 있습니다.(색상, 문자열, 레이아웃값, 표현식 등)

3. CSS 커스텀 속성 사용하기

커스텀 속성을 사용하려면 var() 함수 안에 속성 이름을 적어 사용합니다.

var() 함수는 fallback을 제공합니다.
이는 쉼표로 구분되는데, var() 함수 안에서 첫 번째 쉼표 뒤의 값이 fallback으로 간주됩니다.

var() 함수 문법: var( <custom-property-name> [, <declaration-value> ]? )

첫번째 인수는 대체할 커스텀 속성 이름을 적습니다. 두번째 인수는 대체 값으로, 커스텀 속성이 유효하지 않을 경우 사용됩니다.

See the Pen VWrmJV by WITBLOG (@witblog) on CodePen.

(1) 연산자

커스텀 속성 사용시 기본 연산자를 사용 하고자 할때는 CSS가 제공하는 calc() 함수를 사용합니다. 이는 커스텀 속성의 값을 변경한 후 브라우저가 표현식을 재계산하게 합니다.

아래와 같이 사용할 수 있습니다.

See the Pen wePgvB by WITBLOG (@witblog) on CodePen.

단위가 없는 경우, calc() 함수가 없다면 작동하지 않을 것입니다.

See the Pen YQENzB by WITBLOG (@witblog) on CodePen.

(2) 키워드

CSS 커스텀 속성은 일반적인 CSS 속성과 같은 규칙을 가지고 있기때문에, inherit, initial, unset, revert와 같은 일반적인 CSS 키워드를 지정할 수 있습니다.

  • inherit
    • 부모 요소의 값을 적용한다.
  •  initial
    • CSS 스펙에 정의된 초기값을 적용한다. (CSS 커스텀 속성의 일부 경우, 초기값이 빈 값이거나 없다.)
  •  unset
    • 속성이 상속되었으면 커스텀 속성의 경우처럼 상속된 값을 적용하고, 속성이 상속되지 않았으면 초기값을 적용한다.
  •  revert
    • 속성을 user agent’s style sheet에 의해 초기값으로 리셋한다.(CSS 커스텀 속성의 경우, 초기값은 빈 값이다.)
요소에 모든 스타일을 리셋하기 위해서는 all 키워드를 사용할 수 있습니다.
안타깝게도, all 키워드는 커스텀 속성은 리셋하지 못하며 모든 CSS 커스텀 속성을 리셋하는 -- 접두사를 추가할지에 대한 논의가 진행되고 있습니다. 미래에는 다음과 같이 전체 리셋이 가능할지도 모릅니다.

4. 스코프(scope)와 상속

CSS 커스텀 속성의 스코프를 설명하기에 앞서, 자바스크립트와 전처리기의 스코프에 대해 알아봅시다.

(1) 자바스크립트

자바스크립트는 지역변수와 전역변수가 있으며, 변수(var)는 함수에 제한됩니다.  하지만 자바스크립트에는 클로저(closure)라는 개념이 있어서, 자신을 감싸는 외부 함수의 변수에 접근 가능합니다. (스코프 체인)
클로저에는 세 개의 스코프 체인이 있으며, 다음과 같은 항목에 접근할 수 있습니다.

  • 자신의 스코프 (중괄호 사이에 정의된 변수)
  • 외부 함수의 변수
  • 전역 변수

(2) 전처리기

대표적인 전처리기인 Sass는 지역변수와 전역변수가 있습니다. (mixin과 같이 선택자 밖에 선언될 경우 전역변수 / 그렇지 않으면 지역변수) Sass는 중첩된 코드 블록에서 자신을 감싸는 블록의 변수에 접근 가능합니다. Sass에서 변수의 스코프는 코드 구조에 완전히 의존합니다.

See the Pen YQEVpe by WITBLOG (@witblog) on CodePen.

(3) CSS 커스텀 속성

커스텀 속성은 선택자 외부에서 선언할 수 없으며, :root 스코프 내에 정의된 경우만 전역으로 사용할 수 있습니다. CSS 커스텀 속성은 기본적으로 상속되며, 다른 CSS 속성과 같이 캐스케이딩 합니다.

See the Pen XgzRNK by WITBLOG (@witblog) on CodePen.

5. 전처리기 vs CSS 커스텀 속성

(1) 커스텀 속성을 바꾸면 모든 인스턴스에 즉시 적용된다.

위의 예시로 볼때, CSS 커스텀 속성은 Sass 변수와 다른 점이 없어보입니다. 이번에는 변수를 사용한 후에 다시 할당해봅시다.

먼저 Sass를 사용해보겠습니다.

See the Pen MoOmbw by WITBLOG (@witblog) on CodePen.

아래는 CSS 커스텀 속성을 사용한 경우입니다.

See the Pen BZmRLv by WITBLOG (@witblog) on CodePen.

여기서 전처리기와 CSS 커스텀 속성의 첫번째 차이를 알 수 있습니다.

Sass는 변수를 다시 할당해도 결과에 아무 영향이 없지만,CSS 커스텀 속성 사용시 변수 값을 다시 할당하면 브라우저는 모든 변수와 calc() 함수를 재계산합니다.

(2) 전처리기는 DOM 구조를 알지 못한다.

아래와 같이 highlighted 클래스를 제외하고는 기본 폰트사이즈를 사용하는 예를 생각해봅시다. 먼저 CSS 커스텀 속성을 사용해보겠습니다.

See the Pen vZWmXR by WITBLOG (@witblog) on CodePen.

위의 예에서 두번째 div는 default 외에도 highlighted 클래스를 가지고 있기 때문에 –highlighted-size와 –default-size 커스텀 속성 모두 선언된 상태입니다. 따라서 font-size는 –highlighted-size인 30px이 적용됩니다.

CSS 커스텀 속성은 DOM 구조를 이해하며, 다른 CSS 속성과 같은 규칙을 따라 캐스케이딩할 수 있습니다.

브라우저 동작 원리: (참고: http://d2.naver.com/helloworld/59361)

렌더링 엔진은 HTML 문서를 파싱하고 ‘콘텐츠 트리’ 내부에서 태그를 DOM 노드로 변환합니다. 그 다음 외부 CSS 파일과 함께 포함된 스타일 요소도 파싱합니다. 스타일 정보와 HTML 표시 규칙은 ‘렌더트리’라고 부르는 또 다른 트리를 생성합니다.

이번에는 Sass를 사용해봅시다.

아래에서 사용된 ‘variable-exists’ 함수는 주어진 이름의 변수가 현재 범위 또는 지역 범위에 있는지 확인합니다.

See the Pen yXPbJL by WITBLOG (@witblog) on CodePen.

지역 변수는 범위 내에서만 사용 가능하기 때문에, default 클래스의 범위 내에서 highlighted-size 변수는 접근 불가하며, default-size 변수만 사용 가능합니다. 따라서 default highlighted 클래스를 가진 요소더라도  font-size는 default-size인 10px이 적용됩니다.

여기서 중요한 것은 전처리기는 컴파일 과정을 거치기 때문에 모든 계산과 처리가 동시에 일어난다는 것입니다. 그렇기 때문에 전처리기는 컴파일하기 이전의 코드 구조에 완전히 의존하고, DOM의 구조는 전혀 알지 못합니다.

컴파일 과정:
CSS 전처리기는 코드를 작성한 뒤, CSS 문법으로 컴파일 해주는 방식을 취합니다.

이것이 전처리기와 CSS 커스텀 속성의 두번째 차이입니다. CSS 커스텀 속성은 DOM 구조를 인식하고, 동적이기 때문에 변수 스코프 지정시 이점을 가집니다.

6. 자바스크립트와 함께 사용하기

이전에 CSS에서 자바스크립트로 데이터를 보내기위해서는 CSS 출력에서 JSON을 통해 CSS 값을 작성한 후, 자바스크립트에서 읽어야 했습니다.

이제는 .getPropertyValue() 와 .setProperty() 메소드를 사용하여 자바스크립트에서 CSS 커스텀 속성을 읽고 쓸 수 있습니다.

아래는 CSS 커스텀 속성을 읽어오고, 내보내는 메서드입니다.

See the Pen eReWEz by WITBLOG (@witblog) on CodePen.

7. CSS 커스텀 속성 활용하기

CSS 커스텀 속성을 사용한 사례가 많으나, 그 중 가장 많이 사용하고, 흥미로운 사례들을 소개합니다.

(1) 존재하지 않는 CSS 규칙 생성

CSS “커스텀” 속성이므로 존재하지 않는 속성을 만들 수 있습니다. 예를 들면, translateX/Y/Z, background-repeat-x/y, box-shadow-color등이 있습니다. 그 중 box-shadow-color 커스텀 속성을 만들어 봅시다.

See the Pen EXbmpX by WITBLOG (@witblog) on CodePen.

이처럼 box-shadow의 전체 값을 다시 입력하는 대신, 원하는 부분만 대체할 수 있습니다.

(2) 컬러 테마

컬러 테마는 CSS 커스텀 속성을 사용하는 가장 일반적인 사례 중 하나입니다. 간단한 컬러 테마를 적용해봅시다.

body 요소에 클래스명을 추가한 경우에 다른 스타일을 주고싶다면 아래와 같이 override할 수 있습니다.

CSS 전처리기는 이 작업을 수행하기 위해서는 CSS 코드를 중복하는 오버헤드가 필요합니다. 하지만 CSS 커스텀 속성을 사용하면 한가지 값만 재정의하면 되기 때문에 명확하고, 복사/붙여넣기를 피할 수 있습니다.

CSS 커스텀 속성을 사용하면, 아래와 같이 사용자가 직접 테마 색상을 선택하는 코드도 구현할 수 있습니다.

See the Pen VbqBeP by Kong Jeongmin (@hihelloho) on CodePen.

(3) 미디어쿼리

커스텀 속성을 사용하여 미디어쿼리를 작성해봅시다.

CSS 출력은 아래와 같습니다.
일반적으로 작성하는 것과 CSS 결과는 동일하지만, CSS 커스텀 속성을 사용하면 훨씬 간단하며 이해하기 쉽습니다. 커스텀 속성을 사용하면 모든 요소의 전환점마다 새로운 속성을 지정할 필요가 없습니다.

8. 브라우저 지원

CSS 커스텀 속성을 지원하는 브라우저는 아래와 같습니다. (참고: http://caniuse.com/#search=Custom%20Properties)

(1) @supports

만약 하위 브라우저를 지원해야 하는 경우, @supports를 사용합니다.

@supports:

@supports는 지원하는 경우에만 적용되고, 지원하지 않으면 넘어갑니다.
즉, 이해하지 못하는 소스는 무시하기 때문에 대체 기능을 제공할 수 있습니다.

괄호 안에는 커스텀 속성과 값을 넣습니다. (ex. --color: red)

자바스트립트에서도 CSS.supports() 메소드를 사용할 수 있습니다.

위와 같이 @supports를 사용할 경우, 제대로 작동하고 바로 수행할 수 있다는 장점이 있지만, 코드가 복잡해질 수 있습니다.

그렇기 때문에 자동으로 CSS 결과를 처리하는 플러그인을 사용하는 방법도 있습니다. (PostCSS에서 제공하는 postcss-custom-properties)

(2) 중복 사용하기

하위 브라우저를 지원하기 위해, CSS의 특징을 활용할 수 있습니다.

위와 같이 사용하면, 먼저 color: red 가 적용된 다음, CSS 커스텀 속성이 적용됩니다. 비록 속성을 중복 사용하지만, 기존에 사용하는 코드 내에서 CSS 커스텀 속성을 쉽게 사용할 수 있습니다.

즉, 브라우저가 CSS 커스텀 속성을 지원하지 않더라도 쉽게 리팩토링할 수 있습니다.

9. 결론

지금까지 CSS 커스텀 속성에 대해 알아보았으며, 전처리기와 어떤 점이 다른지 살펴보았습니다. 이 둘의 장점을 비교해보면 아래와 같습니다.

CSS 커스텀 속성
전처리기
전처리기 없이 사용 가능하다 브라우저 지원을 고려할 필요가 없다
캐스케이딩 한다 단위를 제거할 수 있다
값이 바뀌면 브라우저가 재계산한다
자바스크립트에서 다룰 수 있다

그동안 CSS 전처리기를 사용해왔지만, CSS 커스텀 속성의 장점도 많기 때문에 사용해보아도 좋을 것 같습니다.

이상으로 CSS 커스텀 속성 정리를 마치겠습니다. CSS 커스텀 속성을 이해하는데 조금이나마 도움이 되셨길 바랍니다. 긴 글 읽어주셔서 감사합니다. (웃음)

* 참고 자료:

– https://www.smashingmagazine.com/2017/04/start-using-css-custom-properties/ (CSS 커스텀 속성)
– https://www.mikestreety.co.uk/blog/css-custom-properties-everyday-applications (CSS 커스텀 속성)
– https://css-tricks.com/css-custom-properties-theming/ (CSS 커스텀 속성과 테마 적용하기)
– https://css-tricks.com/difference-between-types-of-css-variables/ (CSS 변수와 전처리기 변수의 차이)
– https://csswizardry.com/2016/10/pragmatic-practical-progressive-theming-with-custom-properties/ (실용적이고 진보적인 CSS 커스텀 속성)
– https://www.w3.org/TR/css-variables/
– https://developer.mozilla.org/– http://caniuse.com/
– https://una.im/local-css-vars/?utm_source=CSS-Weekly&utm_campaign=Issue-269&utm_medium=web (지역범위 CSS 커스텀 속성)