색이 안 맞는 화면은 이유를 딱 짚기 어려운데, 대개는 감이 아니라 색상환 위에서 각도가 어긋난 경우입니다. 색을 코드로 적어 두면 조화가 계산으로 풀립니다. 아래 예제는 모두 그대로 복사해 확인할 수 있습니다.

47.1 색을 코드로 적는 세 가지 표기

같은 파란색도 세 가지 방식으로 쓸 수 있습니다. 조화를 다룰 때는 hsl이 압도적으로 편한데, 색상이 각도 하나로 드러나기 때문입니다.


.a { color: #2563eb; } /* 16진수 */
.b { color: rgb(37, 99, 235); } /* 빨강 초록 파랑 */
.c { color: hsl(221, 83%, 53%); } /* 색상 채도 명도 */


세 줄은 완전히 같은 색을 가리킵니다. hsl의 첫 값 221이 색상환 위의 각도이고, 이 각도만 돌리면 이웃한 색과 반대색을 바로 찾을 수 있습니다.

47.2 색상환은 결국 hue 각도

색상환을 한 바퀴 돌면 0도에서 360도까지의 hue가 됩니다. 채도와 명도를 고정하고 hue만 바꾸면 색상환을 코드로 훑는 셈입니다.


:root {
--s: 70%;
--l: 50%;
}
.red { background: hsl(0 var(--s) var(--l)); }
.yellow { background: hsl(60 var(--s) var(--l)); }
.green { background: hsl(120 var(--s) var(--l)); }
.cyan { background: hsl(180 var(--s) var(--l)); }
.blue { background: hsl(240 var(--s) var(--l)); }
.magenta { background: hsl(300 var(--s) var(--l)); }


0은 빨강, 120은 초록, 240은 파랑입니다. 세 색이 120도씩 균등하게 놓여 있어서, 이 간격을 그대로 쓰면 뒤에 나올 삼색 조화가 됩니다.

47.3 보색은 hue에 180 더하기

정반대 색은 각도를 반 바퀴 돌린 값입니다. 기준 색을 변수로 잡아 두면 보색은 계산 한 번으로 나옵니다.


:root {
--base-h: 221;
}
.brand {
background: hsl(var(--base-h) 83% 53%);
}
.accent {
/* 221 + 180 = 401, 즉 41도 */
background: hsl(calc(var(--base-h) + 180) 83% 53%);
}


파란 브랜드색의 보색은 주황 계열이 됩니다. 보색은 서로를 가장 튀게 만들어서 강조 버튼이나 알림 배지에 쓰면 시선이 확 붙습니다. 다만 넓은 면적에 반반 쓰면 눈이 피로하니 한쪽은 좁게 쓰는 편이 좋습니다.

47.4 유사색은 hue를 조금만 돌리기

기준색 양옆으로 30도 안쪽에 있는 색끼리는 자연스럽게 어울립니다. 잔잔한 배경 그라데이션이나 카드 묶음에 잘 맞습니다.


:root { --h: 210; }
.c1 { background: hsl(calc(var(--h) - 30) 65% 55%); }
.c2 { background: hsl(var(--h) 65% 55%); }
.c3 { background: hsl(calc(var(--h) + 30) 65% 55%); }


180도쯤의 청록에서 240도쯤의 남색까지, 파랑 한 계열 안에서 부드럽게 이어집니다. 대비가 약한 대신 통일감이 강해서 편안한 인상을 줍니다.

47.5 삼색과 분리 보색

색상환을 삼등분한 세 색은 활기차면서도 균형이 잡힙니다. 보색이 너무 강할 때는 보색의 양옆을 쓰는 분리 보색으로 누그러뜨립니다.


:root { --h: 0; } /* 빨강 기준 */
/* 삼색: 0, 120, 240 */
.t1 { background: hsl(var(--h) 70% 55%); }
.t2 { background: hsl(calc(var(--h) + 120) 70% 55%); }
.t3 { background: hsl(calc(var(--h) + 240) 70% 55%); }
/* 분리 보색: 0, 150, 210 */
.s1 { background: hsl(var(--h) 70% 55%); }
.s2 { background: hsl(calc(var(--h) + 150) 70% 55%); }
.s3 { background: hsl(calc(var(--h) + 210) 70% 55%); }


삼색은 세 각이 정삼각형을 이루고, 분리 보색은 보색인 180도를 피해 150도와 210도로 살짝 벌어집니다. 후자가 조금 더 차분합니다.

47.6 채도와 명도로 톤 맞추기

hue만 맞아도 채도와 명도가 제각각이면 팔레트가 겉돕니다. 여러 색을 나란히 쓸 때는 뒤의 두 값을 묶어 두는 편이 안전합니다.


:root {
--s: 68%;
--l: 52%;
}
.ok-1 { background: hsl(210 var(--s) var(--l)); }
.ok-2 { background: hsl(150 var(--s) var(--l)); }
.ok-3 { background: hsl(30 var(--s) var(--l)); }


세 색이 다른 계열인데도 채도와 명도가 같아서 한 가족처럼 보입니다. 톤을 통일하면 색을 여러 개 써도 산만해지지 않습니다.

47.7 안 맞는 팔레트 고치기

흔한 실패는 채도가 뒤죽박죽인 경우입니다. 쨍한 원색과 탁한 색을 섞으면 아래처럼 겉돕니다.


/* 나쁜 예: 채도 명도가 제각각 */
.bad-1 { background: hsl(210 95% 45%); }
.bad-2 { background: hsl(150 25% 70%); }
.bad-3 { background: hsl(30 100% 50%); }


하나는 쨍하고 하나는 흐릿하니 같은 화면에 두면 따로 놉니다. hue는 유지한 채 채도와 명도만 한 값으로 모아 주면 정돈됩니다.


/* 좋은 예: 톤 통일 */
.good-1 { background: hsl(210 60% 52%); }
.good-2 { background: hsl(150 60% 52%); }
.good-3 { background: hsl(30 60% 52%); }


같은 세 각도인데 이제 한 벌처럼 어울립니다. 색 고민의 절반은 hue 조합, 나머지 절반은 채도와 명도를 묶는 일입니다.

47.8 한 색에서 명암 단계 뽑기

버튼의 기본, 호버, 눌림 상태처럼 한 색의 여러 단계가 필요할 때가 많습니다. hue와 채도는 그대로 두고 명도만 조절하면 자연스러운 계단이 만들어집니다.


:root {
--h: 221;
--s: 83%;
}
.tint { background: hsl(var(--h) var(--s) 72%); } /* 밝게 */
.base { background: hsl(var(--h) var(--s) 53%); } /* 기준 */
.shade { background: hsl(var(--h) var(--s) 38%); } /* 어둡게 */


명도를 72, 53, 38로 내리면 같은 파랑의 밝은 변형과 어두운 변형이 나옵니다. 호버에는 조금 어둡게, 배경에는 아주 밝게 쓰면 색 하나로 컴포넌트 한 벌을 다 꾸릴 수 있습니다.


.btn {
background: hsl(var(--h) var(--s) 53%);
color: #fff;
}
.btn:hover { background: hsl(var(--h) var(--s) 46%); }
.btn:active { background: hsl(var(--h) var(--s) 38%); }


상태가 바뀔 때마다 명도만 한 칸씩 내려가니 색이 튀지 않고 눌리는 느낌만 또렷해집니다.

47.9 정리

색상환은 hue라는 각도 하나로 코드에 들어옵니다. 보색은 180도, 유사색은 30도 안쪽, 삼색은 120도 간격, 이렇게 각을 먼저 정하고 채도와 명도를 한 값으로 묶으면 감이 아니라 계산으로 조화를 맞출 수 있습니다. 색이 안 맞는다 싶으면 대개 각도가 아니라 톤이 어긋난 것입니다.