CSS 변수(custom property — 자료에 따라 사용자 지정 속성)는 값에 이름을 붙여 한 곳에 두고, 쓰는 곳에서 var()로 꺼내 쓰는 것입니다. 이름은 --로 시작합니다.
레시피 노트의 강조색 #005bb5는 네 곳에 있습니다 — 링크, 배지 글자, 입력 칸의 포커스 윤곽선, 단추 바탕입니다. 강조색을 초록으로 바꾸려면 네 곳을 모두 찾아 고쳐야 하고, 하나라도 빠뜨리면 초록 링크 옆에 파란 배지가 남습니다. 색을 변수에 담아 두면 한 줄만 고칩니다. JavaScript의 변수(값에 붙인 이름)와는 다릅니다 — CSS 변수는 글자색처럼 물려받습니다.
그림 준비 중
1:root에 두고 var()로 꺼낸다
<a href="japchae.html">잡채</a>
:root {
--accent: #005bb5;
}
a {
color: var(--accent);
}:root의--accent#005bb5a의 글자색rgb(0, 91, 181)
| 부분 | 하는 일 |
|---|---|
:root | 문서의 뿌리 요소를 고르는 가상 클래스 — HTML에서는 html |
--accent: #005bb5; | 변수를 만든다. 선언과 모양이 같고 이름이 --로 시작한다 |
var(--accent) | 그 자리에 변수의 값을 꺼내 쓴다 |
변수 이름은 대소문자를 가립니다 — --accent와 --Accent는 다른 변수입니다. 변수에는 16px 같은 길이도 담을 수 있지만, 이 과목은 색에만 씁니다.
2변수도 물려받는다
변수를 :root에 두는 까닭은 물려받기입니다. 변수는 글자색처럼 물려받는 값이라, 뿌리에 한 번 두면 그 안의 모든 요소가 물려받아 꺼내 씁니다(브라우저 규칙 5). 그래서 안쪽 요소에 같은 이름을 다시 두면 그 안에서만 값이 바뀝니다.
<p>
<a href="japchae.html">잡채</a>
</p>
<div class="event">
<a href="event.html">행사</a>
</div>
:root {
--accent: #005bb5;
}
.event {
--accent: #15803d;
}
a {
color: var(--accent);
}p a의--accent#005bb5p a의 글자색rgb(0, 91, 181).event a의 글자색rgb(21, 128, 61)
a 규칙은 하나인데 링크 색은 둘입니다. var()는 그 요소가 물려받은 변수 값을 꺼냅니다 — .event 안의 링크는 가장 가까운 조상 .event의 초록을, 문단 안의 링크는 :root의 파랑을 물려받았습니다.
3이름에 오타가 나면 부모의 값
변수 이름이 틀려도 오류는 나지 않습니다. 선언의 꼴은 맞아 그 선언이 이기고, 꺼낼 변수가 없으니 닿는 선언이 없을 때처럼 됩니다 — 물려받는 속성은 부모의 값, 나머지는 처음 값입니다.
<p>
<a href="japchae.html">잡채</a>
</p>
:root {
--accent: #005bb5;
}
p {
color: #1d1d1f;
}
a {
color: var(--acent);
}a의 글자색rgb(29, 29, 31)
c가 하나 빠졌습니다. 링크는 파랑도, 기본 스타일의 링크 색도 아닌 부모 p의 글자색입니다. 같은 오타가 background-color에 있으면 처음 값인 투명이 되어 바탕이 사라집니다.
이름이 맞는지는 개발자 도구에서 봅니다. 요소를 고르고 Styles 창에서 var() 안의 이름에 마우스를 올리면, 있는 변수는 값이 뜨고 없는 변수는 정의되지 않았다는 안내가 뜹니다(크롬 기준).
예제
레시피 노트의 색을 변수 여섯으로 모으기
레시피 노트의 색을 역할 이름으로 :root에 모읍니다. 16단원 다크 모드는 이 여섯의 값만 바꿔 만듭니다.
| 변수 | 역할 | 값 |
|---|---|---|
--bg | 페이지 바탕 | #f5f5f7 |
--surface | 바탕 위에 올라앉은 면(카드 · 칸 · 단추 글자) | #ffffff |
--text | 글자 | #1d1d1f |
--muted | 보조 글자 | #6e6e73 |
--line | 선 | #d2d2d7 |
--accent | 링크 · 강조 · 단추 | #005bb5 |
<a href="japchae.html">잡채</a>
<span class="badge">한식</span>
<label for="q">요리 찾기</label>
<input id="q" />
<button>찾기</button>
:root {
--bg: #f5f5f7;
--surface: #ffffff;
--text: #1d1d1f;
--muted: #6e6e73;
--line: #d2d2d7;
--accent: #005bb5;
}강조색을 쓰는 네 곳에서 --accent를 꺼냅니다.
a,
.badge {
color: var(--accent);
}
button {
color: var(--surface);
background-color:
var(--accent);
}
input:focus-visible {
outline:
3px solid var(--accent);
}a의 글자색rgb(0, 91, 181).badge의 글자색rgb(0, 91, 181)button의background-colorrgb(0, 91, 181)
이제 강조색을 초록으로 바꾸는 일은 --accent 한 줄입니다. 입력 칸을 눌러 포커스를 준 뒤 재면 윤곽선도 초록입니다.
:root {
--accent: #15803d;
}a의 글자색rgb(21, 128, 61).badge의 글자색rgb(21, 128, 61)button의background-colorrgb(21, 128, 61)#q의outline-colorrgb(21, 128, 61)
자주 틀리는 곳
틀린 생각: --를 빠뜨려도 오타처럼 부모의 값이 된다.
<p>
<a href="japchae.html">잡채</a>
</p>
:root {
--accent: #005bb5;
}
p {
color: #1d1d1f;
}
a {
color: var(accent);
}a의 글자색rgb(0, 0, 238)
이번에는 부모의 글자색이 아니라 기본 스타일의 링크 파랑입니다. var() 안은 --로 시작하는 변수 이름이어야 해서, 브라우저가 이 선언을 알아듣지 못해 버렸습니다(브라우저 규칙 4). 버린 선언은 없던 것과 같아 앞 규칙(여기서는 기본 스타일)의 값이 남고, 다른 선언과 규칙은 그대로 먹습니다.
맞는 규칙: 이름 오타는 선언이 이긴 뒤 부모의 값이나 처음 값으로, -- 빠짐은 선언째 버려 앞 규칙의 값으로 갑니다. 결과가 다르니 둘을 가려 찾습니다.
틀린 생각: 변수 이름은 색 이름으로 짓는다.
:root {
--blue: #15803d;
}
강조색을 초록으로 바꾸면 --blue에 초록이 담겨 이름이 거짓말을 합니다. 이름을 고치려면 var(--blue)를 쓴 곳을 모두 찾아야 해 변수를 만든 보람이 사라집니다. 16단원 다크 모드에서 --white 같은 이름이 어두운 색을 담게 되는 것도 같은 문제입니다.
맞는 규칙: 변수 이름은 역할로 짓습니다(--accent · --surface). 5단원에서 클래스 이름을 모양이 아니라 역할로 지은 것과 같습니다.
틀린 생각: 어디에 두든 변수는 페이지 전체에서 꺼내 쓸 수 있다.
<div class="card">카드</div>
<a href="japchae.html">잡채</a>
.card {
--accent: #15803d;
}
a {
color: var(--accent);
}a의 글자색rgb(0, 0, 0)
링크는 초록이 아니라 검정입니다. .card에 둔 변수는 .card와 그 안 요소만 물려받습니다. 형제인 링크에는 닿지 않아, 이름이 틀렸을 때처럼 부모 body의 글자색을 썼습니다.
맞는 규칙: 변수는 물려받는 길(조상에서 후손으로)로만 닿습니다. 페이지 전체에서 쓸 변수는 :root에 둡니다(브라우저 규칙 5).
확인 문제
1. 예제에서 --accent 대신 --surface의 값을 #f5f5f7로 바꿉니다. 색이 바뀌는 곳을 모두 고르세요.
- ㉠ 링크 글자
- ㉡ 배지 글자
- ㉢ 단추 글자
- ㉣ 단추 바탕
힌트
예제의 둘째 CSS에서 var(--surface)를 꺼내 쓰는 선언을 찾아보세요.
정답
㉢입니다.
<button>찾기</button>
:root {
--surface: #f5f5f7;
--accent: #005bb5;
}
button {
color: var(--surface);
background-color:
var(--accent);
}button의 글자색rgb(245, 245, 247)button의background-colorrgb(0, 91, 181)
--surface를 꺼내 쓰는 곳은 단추의color하나라 단추 글자만 바뀝니다.- ㉣도 골랐다면 단추 규칙 전체가 바뀐다고 본 것입니다. 단추 바탕은
--accent를 꺼냅니다.
2. 카드 테두리 색을 선 역할 변수에서 꺼내 쓰려 합니다. ____ 자리를 채우세요.
:root {
--line: #d2d2d7;
}
.card {
border: 1px solid ____;
}
힌트
1절 표에서 변수의 값을 꺼내 쓰는 꼴을 찾아보세요.
정답
var(--line)입니다.
<div class="card">잡채</div>
:root {
--line: #d2d2d7;
}
.card {
border:
1px solid var(--line);
}.card의border-top-colorrgb(210, 210, 215)
--line만 쓰면 변수 이름이지 값을 꺼내는 꼴이 아니라 선언째 버려집니다. var()로 감싸야 합니다.
3. 플로우 카페 메뉴판의 할인 띠입니다. 띠의 바탕은 무엇으로 보일까요?
<p class="sale">쿠키 2000</p>
:root {
--sale: #d70015;
}
.sale {
background-color: #ffa500;
}
.sale {
background-color: var(--sal);
}
- ① 빨강
#d70015 - ② 주황
#ffa500 - ③ 바탕 없음(투명)
힌트
둘째 .sale 규칙의 var() 안 이름을 :root의 이름과 한 글자씩 견줘 보세요.
힌트 둘
이름 오타는 선언을 버리지 않습니다. 이긴 선언이 꺼낼 변수가 없을 때 background-color는 무엇을 쓰는지 3절에서 찾아보세요.
정답
③입니다.
.sale의background-colorrgba(0, 0, 0, 0)
- 둘째 규칙의 선언은 꼴이 맞아 첫째 규칙을 이기고, 꺼낼
--sal이 없습니다.background-color는 물려받지 않는 속성이라 처음 값인 투명이 됩니다. - ②는 앞 규칙으로 돌아간다고 본 것입니다. 앞 규칙으로 가는 것은
--를 빠뜨려 선언째 버렸을 때입니다. ①은 오타를 브라우저가 고쳐 읽는다고 본 것입니다.
컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요.
예제의 HTML과 두 CSS를 index.html과 style.css로 저장하고 link로 이어 엽니다(문서 뼈대의 body 안에 예제 HTML을 넣습니다). --accent 한 줄을 #d70015로 바꾸면 어디가 바뀔지 먼저 적고, 저장한 뒤 새로고침해 링크 · 배지 · 단추를 보고 입력 칸을 눌러 윤곽선을 봅니다.