게시일: 2025년 12월 11일
빌드하거나 재설계하려는 사이트가 있습니다. 몇 가지 핵심 색상을 염두에 두고 이러한 색상을 기반으로 테마를 빠르게 구현하는 방법을 생각하고 있을 수도 있습니다.
기본 색상뿐만 아니라 작업, 마우스 오버 상태, 오류 색상, 기타 사용자 인터페이스 요구사항에 필요한 색상도 필요합니다. 밝은 모드와 어두운 모드 옵션은 어떻게 되나요? 갑자기 필요한 색상이 많아져서 부담스러울 수 있습니다.
좋은 소식은 사이트를 정의하는 색상 토큰을 기준으로 팔레트를 빌드하고 색상 모드 간에 전환할 때 기준 기능이 많은 작업을 대신 처리해 줄 수 있다는 것입니다. 추천 데모인 가상의 Baseline Radio 사이트의 색상 테마 재생목록에서 이러한 기법을 살펴볼 수 있습니다.
상대 색상으로 기본값 빌드
테마의 기본 색상에 대한 아이디어가 있다면 기본적인 색상 이론과 CSS 상대 색상 구문을 사용하여 테마에서 사용할 색상 팔레트를 빠르게 생성할 수 있습니다.
기본 색상이 청록색이라고 가정해 보겠습니다. 먼저 선호하는 색상 형식으로 정의할 수 있습니다. 그런 다음 색상 함수를 사용하여 기본 색상과 관련된 새 색상을 만들 수 있습니다.
html {
--base-color: oklch(43.7% 0.075 224);
}
--base-color 맞춤 속성은 oklch() 색상 함수를 사용하여 만들어집니다. OkLCh는 Oklab 색상 공간의 원통형이며, L (명도), C (채도), H (색조)의 세 가지 채널 값과 투명도를 제어하는 선택적 알파 채널을 정의합니다.
OkLCh는 지각적 균일성을 제공하도록 설계되었으므로 이러한 유형의 색상 조작에 적합한 형식입니다. 예를 들어 색상의 색조만 조정하면 결과 색상의 인식된 명도와 채도가 원래 색상과 비슷해야 합니다. 이는 예기치 않은 대비 문제를 방지하는 데 특히 유용합니다.
--base-color의 명도와 채도를 동일하게 유지하면서 삼색 팔레트를 위해 양방향으로 색조를 120도 조정할 수 있습니다.
html {
/* ... */
--triadic-color-primary: oklch(from var(--base-color) l c calc(h + 120));
--triadic-color-secondary: oklch(from var(--base-color) l c calc(h - 120));
}
여기에 표시된 것처럼 상대 색상 구문은 from 키워드를 사용하여 원본 색상 (이 예에서는 --base-color)을 참조하는 색상 함수를 사용하고 선택한 출력 색상에 따라 색상 공간의 각 채널을 조정합니다. 이 경우 출력 색상도 OkLCh가 됩니다.
결과 출력은 --accent-color에 어두운 분홍색을, --highlight-color에 금색 음영을 제공하며, 둘 다 원래 --base-color와 동일한 명도와 크로마를 갖습니다.
html {
/* ... */
--accent-color: var(--triadic-color-primary);
--highlight-color: var(--triadic-color-secondary);
}
html {
/* Input color in the rgb color space*/
--base-color: teal;
/* Output color in oklch. Computes to oklch(0.543123 0.0927099 314.769) */
--triadic-color-primary: oklch(from var(--base-color) l c calc(h + 120));
}
보색은 색조 각도에 180도를 더합니다.
html {
/* ... */
--complement-color: oklch(from var(--base-color) l c calc(h + 180));
--border-highlight: var(--complement-color);
}
UI의 마우스 오버 상태의 경우 특정 색상의 더 밝은 버전을 출력할 수 있습니다. 즉, 밝기 채널의 값을 늘려야 합니다. 활성 상태의 경우 알파 채널을 조정하여 투명도를 추가하거나 밝기 채널의 값을 줄여 어둡게 할 수 있습니다.
html {
/* Darken the --base-color by 15% */
--base-color-darkened: oklch(from var(--base-color) calc(l * 0.85) c h);
/* Assign this color a meaningful variable name */
--action-color: var(--base-color-darkened);
/* Lighten the --action-color by 15% */
--action-color-light: oklch(from var(--action-color) calc(l * 1.15) c h);
/* Darken the --action-color by 10% */
--action-color-dark: oklch(from var(--action-color) calc(l * 0.9) c h);
}
여기서는 --base-color에서 --action-color을 파생시키고 버튼과 링크에 사용합니다. --action-color에는 밝은색과 어두운색의 두 가지 변형이 있으며, --action-color가 --base-color와 다른 색상에 상대적으로 변경되더라도 계속 적용됩니다.
calc()와 같은 수학 함수를 사용하거나 채널을 완전히 새 값으로 대체하여 채널을 조정할 수 있습니다. 변경되지 않은 채널은 각 문자로 표시됩니다 (예: 변경되지 않은 밝기 값의 경우 l).
color-mix()로 색상 혼합
다른 색상 변형의 경우 유사한 접근 방식을 취하고 --base-color 맞춤 속성의 다른 채널을 조정할 수 있습니다. 또는 color-mix()를 사용하여 디자인의 다른 측면에 기본 색상 힌트를 추가합니다.
--border-color는 기본 색상과 이름이 지정된 색상 grey이 oklab 색상 공간에서 보간된 혼합입니다. 색상 보간 방법으로 사용하면 지각적으로 균일한 결과를 제공합니다.
html {
--base-mix-grey-50: color-mix(in oklab, var(--base-color), grey);
--border-color: var(--base-mix-grey-50);
}
기본적으로 각 색상의 비율은 50% 이지만, 비율을 조정하여 한 색상을 더 두드러지게 하거나 덜 두드러지게 할 수 있습니다.
html {
--background-mix-base-80: color-mix(in oklab,
var(--background-color) 80%,
var(--base-color));
--surface-light: var(--background-mix-base-80);
}
요소에 색상을 추가하는 대신 상대 색상 문법을 사용하여 채도 채널을 조정할 수도 있습니다. 연락처 양식의 텍스트 입력란 테두리는 포커스가 있을 때 약간 더 다채로운 테두리를 갖습니다.
[data-input*="text"] {
--focus-ring: transparent;
/* ... */
&:focus {
--focus-ring: oklch(from var(--border-color) l calc(c + 0.1) h);
}
}
밝은 모드 및 어두운 모드 선택
작업할 색상 세트가 있으면 밝은 모드와 어두운 모드에 다양한 색상을 적용하는 효율적인 방법이 필요합니다.
color-scheme 속성으로 밝은 테마와 어두운 테마 지원 신호 보내기
color-scheme 속성을 사용하면 사이트를 '밝은', '어두운' 또는 두 모드 모두에서 볼 수 있다고 브라우저에 즉시 알릴 수 있습니다. 이 속성은 요소가 편안하게 렌더링될 수 있는 색상 스키마를 브라우저에 알려줍니다.
html {
color-scheme: light dark;
}
:root 의사 요소 또는 html 요소에서 color-scheme: light dark 설정:
- 페이지가 밝은 모드 또는 어두운 모드로 볼 수 있음을 브라우저에 알립니다.
- 브라우저 사용자 인터페이스의 기본 색상을 해당 운영체제 설정과 일치하도록 변경합니다.
페이지에서 밝은 모드와 어두운 모드를 지원한다는 사실을 사용자 에이전트에게 더 일찍 알리려면 문서의 <head>에 <meta> 요소를 추가하여 색상 구성표 전환 지원을 알릴 수도 있습니다.
<head>
<!-- ... -->
<meta name="color-scheme" content="light dark">
</head>
light-dark() 함수로 'light' 및 'dark' 변형 설정
작성자는 prefers-color-scheme @media 쿼리를 사용하여 페이지의 색상을 설정하는 데 익숙할 수 있습니다.
@media (prefers-color-scheme: light) {
html {
--background-color: oklch(95.5% 0 162);
--text-color: black;
}
}
@media (prefers-color-scheme: dark) {
html {
--background-color: oklch(22.635% 0.01351 291.83);
--text-color: white;
}
}
이는 작성자가 제어하는 색상과 스타일에는 적합하지만 이전 섹션에서 언급한 것처럼 브라우저 UI의 색상을 업데이트하려면 여전히 color-scheme가 필요합니다.
prefers-color-scheme 쿼리를 사용하여 페이지의 색상을 변경하면 각 모드의 색상을 별도로 정의해야 하므로 코드 중복도 발생합니다.
전체 페이지 (또는 특정 요소)에 color-scheme를 설정하면 light-dark() 함수를 사용하여 한 줄의 코드에서 각 모드의 색상을 설정할 수 있습니다.
이 함수는 두 가지 색상을 허용합니다. 첫 번째는 색 구성표가 '밝음'으로 설정된 경우에 사용되고 두 번째는 색 구성표가 '어두움'으로 설정된 경우에 사용됩니다.
html {
color-scheme: light dark;
/* Color custom property values for both light and dark modes */
--base-color: light-dark(oklch(43.7% 0.075 224), oklch(89.2% 0.069 224));
--background-color: light-dark(oklch(95.5% 0 162), oklch(22.635% 0.01351 291.83));
--accent-color: oklch(from var(--base-color) l c calc(h + 120));
--active-color: light-dark(var(--action-color-light), var(--action-color-dark));
/* ... */
}
모든 맞춤 속성과 마찬가지로 색상의 light-dark() 설정은 전역으로 또는 특정 구성요소 내에서 설정한 후 필요에 따라 다른 곳에서 사용할 수 있습니다.
/* custom property usage */
body {
background-color: var(--background-color);
/* ... */
}
:any-link {
/* ... */
text-decoration-color: var(--accent-color);
}
기본 제공 테마 전환기로 사용자에게 관리 권한 부여
사용자의 기본 시스템 또는 브라우저 색상 환경설정에 적응하는 테마를 사용하는 것도 좋지만, 한 단계 더 나아가 사이트 방문자가 이러한 기본 색상 환경설정을 재정의할 수 있도록 할 수 있습니다.
<html> 요소의 data-scheme 속성을 업데이트하는 테마 전환 버튼을 빌드하는 경우 동일한 속성을 사용하여 CSS로 color-scheme를 변경할 수 있습니다.
html {
color-scheme: light dark;
&[data-scheme="light"] {
color-scheme: light;
}
&[data-scheme="dark"] {
color-scheme: dark;
}
&[data-scheme="green"] {
--base-color-light: oklch(48.052% 0.11875 151.945);
--base-color-dark: oklch(92.124% 0.13356 151.558);
color-scheme: light dark;
}
}
data-scheme="light" 및 data-scheme="dark"는 각각의 색상 모드로만 페이지를 표시합니다. data-scheme="green"는 두 모드에서 모두 볼 수 있으며 --base-color을 녹색 음영으로 변경하므로 대부분의 다른 색상이 --base-color을 기반으로 하기 때문에 완전히 새로운 팔레트가 제공됩니다.
@property로 맞춤 속성 등록
지금까지 데모의 색상은 표준 맞춤 속성으로 설정되었습니다. @property 규칙으로 속성을 등록하여 유형 검사와 관련된 이점을 활용할 수도 있습니다.
--base-color는 인터페이스의 다른 많은 색상의 기반으로 사용되므로 항상 색상이고 대체 값이 있는지 확인하는 것이 좋습니다.
@property --base-color-light {
syntax: '<color>';
inherits: false;
initial-value: oklch(43.7% 0.075 224);
}
@property --base-color-dark {
syntax: '<color>';
inherits: false;
initial-value: oklch(89.2% 0.069 224);
}
html {
--base-color: light-dark(var(--base-color-light), var(--base-color-dark));
}
이렇게 하면 --base-color이 실수로 유효하지 않은 값으로 변경되더라도 항상 @property 규칙으로 설정된 initial-value으로 대체됩니다.
이 방식으로 특정 속성을 등록하면 linear-gradient()에서 색상을 매끄럽게 애니메이션 처리할 수도 있습니다.
.main-heading {
background: linear-gradient(in oklch 90deg, var(--text-color) 50%, oklch(from var(--base-color) l c var(--header-hue)));
background-clip: text;
color: transparent;
animation: header-hue-switch 5s ease-in-out infinite alternate;
}
.main-heading에는 background-clip 속성을 사용하여 투명한 텍스트를 통해 표시되는 linear-gradient() 배경이 있습니다.
텍스트의 일부에는 상대 색상 구문을 사용하여 채널 값 26.67에서 277로 애니메이션을 적용하는 hue가 표시됩니다.
@keyframes header-hue-switch {
from {
--header-hue: 26.67;
}
to {
--header-hue: 277;
}
}
등록된 --header-hue 맞춤 속성을 사용하면 브라우저가 이 맞춤 속성이 숫자임을 알기 때문에 애니메이션이 원활하게 진행될 수 있습니다.
@property --header-hue {
syntax: '<number>';
inherits: false;
initial-value: 100;
}
등록되지 않은 맞춤 속성을 사용하면 브라우저가 --header-hue의 데이터 유형을 알 수 없으므로 숫자로의 전환은 불연속 애니메이션이 되어 점진적인 보간 없이 상태 간에 점프합니다.
마무리
새로운 기준 도구를 사용하면 조정 가능한 색상 팔레트를 빠르게 빌드하고 색상 변수를 더 효율적으로 만들 수 있습니다. 하지만 끝없는 색상 옵션과 조합은 직접 고민해야 합니다.
이와 같이 동적으로 팔레트를 만들면 유연성이 확보됩니다. 브랜딩의 기본 색상을 변경해야 하는 경우 --base-color만 업데이트하면 나머지 테마가 그에 따라 변경됩니다. 또는 음악 재생 기능을 추가하는 경우 현재 재생 중인 노래와 일치하도록 기본 색상을 동적으로 변경할 수 있습니다.
크레딧
Adam Argyle의 테마 전환 구성요소에서 적용된 테마 전환기 로직