호버 색을 눈대중으로 정하다가 color-mix()로 한 곳에서 파생시킨 과정
문제 발생
버튼 색마다 hover와 disabled 변형을 손으로 골라 토큰을 만들었습니다. 서비스가 늘 때마다 이 작업이 그대로 반복됐고, 어떤 색은 hover가 거의 티가 안 나고 어떤 색은 너무 어두워졌습니다.
--btn: #3b6cb7;
--btn-hover: #33619f; /* 눈대중 */
--btn-disabled: #a9bcd8; /* 눈대중 */원인 분석
문제는 두 가지였습니다. 파생 관계가 코드에 없다는 것 — hover가 기준 색에서 어떻게 나왔는지 값만 봐서는 알 수 없습니다. 그리고 색공간 — RGB에서 검정을 섞으면 색상마다 어두워지는 정도가 달라, 같은 비율로 섞어도 결과의 인상이 제각각입니다.
color-mix()는 두 색을 지정한 색공간에서 섞습니다. 2023년 5월부터 Baseline입니다.
color-mix(in oklab, #a71e14 50%, white)색공간 선택이 중요합니다. MDN은 sRGB를 피하라고 명시합니다 — 선형도 지각적으로 균일하지도 않아 결과가 지나치게 어둡거나 회색빛이 됩니다. Oklab/Oklch는 지각적으로 균일해서 같은 비율이 어떤 색에서든 비슷한 정도의 변화로 느껴집니다.
퍼센트 규칙도 알아 둘 만합니다.
- 둘 다 생략하면 각각 50%입니다.
- 하나만 적으면 나머지가 자동으로 채워집니다 —
#a71e14 25%, white는 white가 75%입니다. - 합이 100%가 아니면 정규화하고, 그 합이 알파 배수로 적용됩니다. 그래서
color-mix(in srgb, red 25%, transparent 25%)는 "50% 불투명한 빨강"이 됩니다.
해결 방안
- 기준 색 하나에서 상태 색을 파생시킵니다. 관계가 코드에 남습니다.
:root { --btn: oklch(55% 0.12 255); }
.btn { background: var(--btn); }
.btn:hover { background: color-mix(in oklab, var(--btn) 85%, black); }
.btn:disabled { background: color-mix(in oklab, var(--btn) 35%, white); }- 투명도는
transparent와 섞어 만듭니다. 알파 채널을 따로 관리하지 않아도 되고, 임의의 배경 위에서 예측 가능합니다. 이 저장소도 상태색 배경을 이렇게 만듭니다.
.badge { background: color-mix(in oklch, var(--danger) 10%, var(--surface)); }- 색상환을 도는 방향이 문제가 되면 명시합니다.
hsl·lch·oklch같은 극좌표 색공간에서는shorter hue(기본),longer hue,increasing hue,decreasing hue를 고를 수 있습니다. oklch()로 팔레트를 정의하면 파생이 더 예측 가능해집니다. 명도(L)·채도(C)·색상(H)이 분리돼 있어, "명도는 유지하고 채도만 낮춘다" 같은 조정이 값 하나로 끝납니다. 이 저장소가 서비스별 hue만 바꿔 팔레트를 구성하는 것도 같은 이유입니다.- 대비는 계산으로 확인합니다. 지각적으로 균일한 색공간을 써도 WCAG 대비가 자동으로 보장되지는 않습니다. 버튼 위 글자색은 실제 대비를 재서 확인해야 합니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.