클론코딩을 하려고 웹사이트의 코드를 뜯어보면 처음 보는 :root
가상선택자와 알 수 없는 속성들 --font-family-roboto
같은 것들이 종종 보여 이에 대해 정리하려고 합니다.
CSS 전처리기는 웹 개발에서 중요한 역할을 하고 있다. (Sass, Stylus, Less 등)
전처리기의 주요 장점 중 하나는 변수를 사용할 수 있다는 것이다. 변수를 사용하면 복사 붙여넣기를 피할 수 있고 개발과 리펙토링이 간단해진다.
그러나, 전처리기 변수에는 몇 가지 한계가 있다.
이러한 문제를 해결하기 위해 css 커스텀 속성이 개발되었다. 전처리기와 css 커스텀 속성은 뭐가 다른걸까?
CSS 커스텀 속성은 작성자가 정의한 속성의 집합이다. 작성자는 임의로 정한 이름의 속성에 임의의 값을 할당할 수 있다. 'CSS 변수'라고 부르기도 하지만 올바른 이름은 'CSS 커스텀 속성'이다.
css 커스텀 속성은 아래와 같이 정의할 수 있다.
:root {
--var-name: value;
}
:root{}
:root는 최상위 엘리먼트, 즉 html을 의미한다.
그렇다면 왜 html 태그를 사용하지 않고 :root라는 가상 선택자를 사용하는걸까?
그 이유는 우선순위 문제때문이다. html태그는 우선순위 점수가 1점이고 :root 가상선택자는 클래스로 간주되어 10점이 된다. 그래서 :root를 사용한다.
:root가 html을 의미하므로 커스텀 속성을 전역으로 사용하고자 할 때, :root{}
에 커스텀 속성을 정의한다.
커스텀 속성은 css 변수처럼 [속성]:[값];
의 구문을 따르기 때문에 반드시 중괄호 내에 정의돼야 한다.
--var-name
커스텀 속성의 이름이다. 이름은 --(이중 하이픈)으로 시작하며, 속성 이름은 작성자가 정의한다.
css 커스텀 속성은 css 변수처럼 보이고 작동하며, 보통은 속성 이름에 작동 방식을 반영한다.
또, 다른 css 속성들과는 달리 css 커스텀 속성은 대소문자를 구분한다.
value
커스텀 속성의 값이다. 값에는 모든 css 값이 들어갈 수 있다.(색상, 문자열, 레이아웃값, 표현식 등)
:root {
--main-color: #f00;
--main-bg: #0f0;
--border-color: #ff0;
--header-height: 70px;
--content-padding: 10px 20px;
--base-line-height: 1.5;
--transition-duration: 0.5s;
--external-link: "external link";
--margin-top: calc(2vh + 20px);
/* 유효 커스텀 속성은 후에 JavaScript에서 재사용될 수 있다. */
--foo: if(x > 5) this.width = 10;
}
커스텀 속성을 사용하려면 var()
함수 안에 속성 이름을 적어 사용한다.
.foo {
color: var(--var-name);
}
var() 함수는 fallback을 제공한다. var()
를 이용하여 여러 개의 대체 변수를 정의할 수 있다.
첫 번째 인수는 대체할 커스텀 속성 이름을 적는다.
두 번째 인수는 대체 값으로, 커스텀 속성이 유효하지 않을 경우 사용된다.
.box {
/* --box-margin은 정의되지 않았기 때문에 20px이 사용된다. */
margin: var(--box-margin, 20px);
/* --box-color가 정의되지 않았다면 --main-color 변수가 사용됩니다. */
--main-color: gold;
background: var(--box-color, var(--main-color));
/* common style */
width: 300px;
font-size: 15px;
}
첫 번째 쉼표와 함수 마지막 사이에 있는 값들은 모두 대체 변수로 간주한다.
예를 들어, var(--foo, red, blue)는 빨강, 파랑의 fallbakc을 정의하고 있다.
커스텀 속성 사용시 기본 연산자를 사용하고자 할 때는 css가 제공하는 calc() 함수를 사용한다. 이는 커스텀 속서으이 값을 변경한 후 브라우저가 표현식을 재계산하게 한다.
다음과 같이 사용할 수 있다.
:root {
--indent-size: 20px;
--indent-xl: calc(2 * var(--indent-size));
--indent-l: calc(var(--indent-size) + 2px);
--indent-s: calc(var(--indent-size) - 2px);
--indent-xs: calc(var(--indent-size) / 2);
}
.box1 {font-size:var(--indent-size);}
.box2 {font-size:var(--indent-xl);}
.box3 {font-size:var(--indent-l);}
.box4 {font-size:var(--indent-s);}
.box5 {font-size:var(--indent-xs);}
단위가 없는 경우, calc() 함수가 없다면 작동하지 않을 것이다.
:root {
--spacer: 10;
}
.box {
padding: var(--spacer)px; /* 작동하지 않음 */
padding: calc(var(--spacer)*1px) 0; /* 작동함 */
}
css 커스텀 속성은 일반적인 css 속성과 같은 규칙을 가지고 있기 때문에 inherit, initial, unset, revert와 같은 일반적인 css 키워드를 지정할 수 있다.
inherit : 부모 요소의 값을 적용
initial: css 스펙에 정의된 초기값을 적용 (css 커스텀 속성의 일부 경우, 초기값이 빈 값이거나 없다.)
unset : 속성이 상속되었으면 커스텀 속성의 경우처럼 상속된 값을 적용하고 속성이 상속되지 않았으면 초기값을 적용한다.
revert : 속성을 user agent’s style sheet에 의해 초기값으로 리셋한다.(CSS 커스텀 속성의 경우, 초기값은 빈 값이다.)
css 커스텀 속성을 일반적으로 어떻게 활용하는지 알아보도록 하자.
css '커스텀' 속성이므로 존재하지 않는 속성을 만들 수 있다. 예를 들어, translateX/Y/Z, background-repeat-x/y, box-shadow-color 등이 있다.
그 중 box-shadow-color 커스텀 속성을 만들어 보자.
.test {
--box-shadow-color: gold;
box-shadow: 0 0 30px var(--box-shadow-color);
}
.test:hover {
--box-shadow-color: blue;
/* box-shadow: 0 0 30px blue; 사용 */
}
이처럼 box-shadow의 전체 값을 다시 입력하는 대신, 원하는 부분만 대체할 수 있다.
컬러 테마는 css 커스텀 속성을 사용하는 가장 일반적인 사례 중 하나이다.
예제를 살펴보자.
.btn {
--shadow-color: #777;
--color: #fff;
text-shadow: 1px 1px 3px var(--shadow-color);
box-shadow: 0px 1px 3px var(--shadow-color);
color: var(--color);
}
body 요소에 클래스명을 추가한 경우에 다른 스타일을 주고 싶다면 아래와 같이 override 할 수 있다.
body.inverted .btn{
--shadow-color: #888;
--color: #000;
}
css 전처리기는 이 작업을 수행하기 위해서는 css 코드를 중복하는 오버헤드가 필요하다. 하지만 css 커스텀 속성 을 사용하면 한가지 값만 재정의 하면 되기 때문에 명확하고, 복사 붙여넣기를 피할 수 있다.
커스텀 속성을 사용하여 미디어쿼리를 작성해보자.
:root {
--gutter: 1rem;
@media (min-width: 40em) {
--gutter: 1.5rem;
}
@media (min-width: 70em) {
--gutter: 2rem;
}
}
div {
padding: var(--gutter);
}
h2 {
margin-bottom: var(--gutter);
}
css 출력은 아래와 같다.
div {
padding: 1rem;
}
h2 {
margin-bottom: 1rem;
}
@media (min-width: 40em) {
div {
padding: 1.5rem;
}
h2 {
margin-bottom: 1.5rem;
}
}
@media (min-width: 70em) {
div {
padding: 2rem;
}
h2 {
margin-bottom: 2rem;
}
}
일반적으로 작성하는 것과 CSS 결과는 동일하지만, CSS 커스텀 속성을 사용하면 훨씬 간단하며 이해하기 쉽습니다. 커스텀 속성을 사용하면 모든 요소의 전환점마다 새로운 속성을 지정할 필요가 없습니다.
CSS 커스텀 속성 | 전처리기 |
---|---|
전처리기 없이 사용 가능하다 | 브라우저 지원을 고려할 필요가 없다 |
캐스케이딩 한다 | 단위를 제거할 수 있다 |
값이 바뀌면 브라우저가 재계산한다 | |
자바스크립트에서 다룰 수 있다 |