HSL 색상 모델
(색조, 채도, 밝기)은 CSS에서 색상을 다룰 때 RGB보다 훨씬 직관적인 방법을 제공해요. 빨강, 초록, 파랑 값을 어떻게 조합해야 원하는 색이 나오는지 감으로 때려맞출 필요 없이, HSL은 우리가 실제로 색을 인식하는 방식 그대로 색상을 표현할 수 있어요. 색을 고르고, 얼마나 선명하게 할지 정하고, 밝기를 조절하면 끝이에요. 많은 개발자들이
rgb()
대신
hsl()
로 넘어가는 이유가 바로 이 사고방식의 전환 덕분이에요.
목차
RGB vs HSL - 핵심 차이점
RGB는 빨강, 초록, 파랑 세 가지 빛 채널을 각각 0에서 255 사이의 값으로 혼합해 색상을 정의해요. 문제는 이 방식이 화면이 픽셀을 렌더링하는 방식이지, 사람이 색을 인식하는 방식이 아니라는 점이에요. RGB에서 파란색을 조금 밝게 만들려면 세 채널 값을 모두 적절한 비율로 조정해야 해요. 밝기만 딱 조절할 수 있는 단일 축이 없거든요.
HSL은 사람이 실제로 색을 묘사하는 방식과 직접적으로 대응해요:
- 색조(Hue) - 실제 색상을 나타내며, 360도 색상환에서의 각도로 표현해요. 빨강은 0도, 초록은 120도, 파랑은 240도예요.
- 채도(Saturation) - 색상의 선명함을 나타내며, 0%(순수한 회색)에서 100%(완전히 선명한 색)까지예요.
- 밝기(Lightness) - 색상의 밝고 어두운 정도를 나타내며, 0%(검정)에서 100%(흰색)까지이고, 50%가 순수한 색이에요.
같은 중간 톤 파란색을 두 형식으로 표현하면 이렇게 달라요:
/* RGB - what do these numbers even mean at a glance? */
color: rgb(70, 130, 180);
/* HSL - instantly readable: blue hue, moderate saturation, medium lightness */
color: hsl(207, 44%, 49%);
둘 다 스틸 블루를 표현해요. 하지만 HSL 버전만 한눈에 의미 있는 정보를 전달해요. 색조는 207(파란 계열), 채도는 44%로 중간 정도, 밝기는 49%로 중간에 위치해요. 색상 선택 도구를 열지 않아도 바로 이해할 수 있어요.
| 속성 | RGB | HSL |
|---|---|---|
| 사람이 읽기 쉬운가 | 거의 불가능 | 가능 |
| 색상 밝기 조절 | 3개 값 모두 조정 | 밝기 값만 조정 |
| 채도 변경 | 3개 값 모두 재계산 | 채도 값만 조정 |
| 색상 팔레트 생성 | 시행착오 반복 | 색조를 각도로 회전 |
| CSS 변수로 테마 구성 | 복잡하고 장황함 | 깔끔하고 예측 가능 |
CSS에서의 HSL 문법
CSS의
hsl()
함수는 CSS3부터 지원됐어요. CSS Color Level 4의 최신 문법에서는
hsl()
안에 네 번째 알파 파라미터를 직접 넣을 수 있어서
hsla()
는 이제 거의 쓸 필요가 없어요:
/* Classic syntax */
color: hsl(207, 44%, 49%);
/* With alpha (transparency) - old way */
color: hsla(207, 44%, 49%, 0.8);
/* Modern CSS Color Level 4 syntax - commas optional, alpha with slash */
color: hsl(207 44% 49%);
color: hsl(207 44% 49% / 0.8);
color: hsl(207 44% 49% / 80%);
모든 주요 브라우저가 두 문법을 모두 지원해요. 쉼표 없는 문법이 CSS가 나아가는 방향이지만, 쉼표 문법은 Internet Explorer 9 이상을 포함한 모든 환경에서 동작해요.
UI 개발에서 HSL이 강한 이유
HSL의 진짜 강점은 색상 변형이 필요한 순간에 드러나요. UI 작업에서는 이런 상황이 끊임없이 발생하거든요.
순식간에 색상 팔레트 만들기
브랜드 색상이
hsl(140, 70%, 45%)
의 선명한 초록이라고 해볼게요. 호버 상태, 비활성화 상태, 연한 배경 색조가 필요하다면, HSL에서는 매번 값 하나만 바꾸면 돼요:
--color-base: hsl(140, 70%, 45%); /* base green */
--color-hover: hsl(140, 70%, 38%); /* darker - just lower lightness */
--color-disabled: hsl(140, 20%, 65%); /* washed out - lower saturation */
--color-tint: hsl(140, 70%, 92%); /* very light background tint */
색상 선택 도구 없이 RGB로 이걸 예측 가능하게 해보세요. 조정할 수 있는 독립된 축이 없기 때문에 정말 어려워요.
유사색과 보색
색조가 색상환의 각도이기 때문에, 조화로운 팔레트 생성이 단순한 산술 연산이 돼요. 유사색은 서로 30도 이내에 있고, 보색은 180도 간격이에요:
--primary: hsl(210, 80%, 50%); /* blue */
--analogous-1: hsl(180, 80%, 50%); /* cyan - 30 degrees left */
--analogous-2: hsl(240, 80%, 50%); /* purple - 30 degrees right */
--complementary: hsl(30, 80%, 50%); /* orange - 180 degrees opposite */
채도와 밝기는 동일하게 유지되기 때문에 색상들이 하나의 통일된 계열처럼 느껴져요. Tailwind CSS나 Material Design 같은 디자인 시스템이 색상 스케일을 프로그래밍 방식으로 생성할 때 바로 이 원리를 활용해요.
실전 CSS 예제
HSL 구성 요소를 CSS 커스텀 프로퍼티로 분리하기
HSL에서 가장 강력한 패턴 중 하나는 세 값을 별도의 CSS 커스텀 프로퍼티로 분리하는 거예요. 이렇게 하면 어디서든 조합해서 사용하고 개별 채널을 즉시 조정할 수 있어요:
:root {
--brand-h: 210;
--brand-s: 80%;
--brand-l: 50%;
--brand-color: hsl(var(--brand-h), var(--brand-s), var(--brand-l));
}
.button {
background-color: var(--brand-color);
}
.button:hover {
/* Just override lightness - no need to redefine the whole color */
background-color: hsl(var(--brand-h), var(--brand-s), 40%);
}
.button:disabled {
background-color: hsl(var(--brand-h), 20%, 70%);
}
hsl()
안에서 CSS 커스텀 프로퍼티를 사용할 때는 쉼표가 필요해요:
hsl(var(--h), var(--s), var(--l))
. 쉼표 없는 최신 문법은 모든 브라우저에서
hsl()
내부의
var()
와 아직 완전히 호환되지 않아요.
전체 색조 스케일 생성하기
디자인 시스템에서는 단일 색상의 9-10가지 음영이 필요한 경우가 많아요(Tailwind의 50에서 950 스케일처럼요). HSL을 사용하면 색조와 채도를 고정한 채 밝기를 일정 간격으로 조절하는 것만으로 전체 스케일을 생성할 수 있어요:
:root {
--blue-50: hsl(210, 80%, 95%);
--blue-100: hsl(210, 80%, 87%);
--blue-200: hsl(210, 80%, 76%);
--blue-300: hsl(210, 80%, 65%);
--blue-400: hsl(210, 80%, 55%);
--blue-500: hsl(210, 80%, 50%); /* base */
--blue-600: hsl(210, 80%, 43%);
--blue-700: hsl(210, 80%, 36%);
--blue-800: hsl(210, 80%, 26%);
--blue-900: hsl(210, 80%, 16%);
}
색상 형식 간의 관계를 더 깊이 알고 싶다면, HEX에서 RGB 변환 가이드 에서 각 형식을 언제 사용해야 하는지를 포함한 CSS 색상 형식 전반을 다루고 있어요.
호버 상태, 테마, 다크 모드
호버 및 포커스 상태
HSL을 사용하면 호버 상태 처리가 매우 간단해져요. 완전히 별도의 색상을 정의하는 대신, 밝기 값만 살짝 조정하면 돼요:
.btn-primary {
background: hsl(210, 80%, 50%);
transition: background 0.2s ease;
}
.btn-primary:hover { background: hsl(210, 80%, 43%); }
.btn-primary:active { background: hsl(210, 80%, 36%); }
.btn-primary:focus-visible {
outline: 3px solid hsl(210, 80%, 70%);
}
모든 상태가 기본 색상과 명확하게 연결되어 있어요. 이 코드를 보는 팀원이라면 각 상태 간의 관계를 즉시 이해할 수 있어요.
HSL 변수로 테마 구성하기
HSL은 현대적인 CSS 테마 구성의 핵심이에요. 색조만 변수로 노출하면, 사용자나 관리자가 숫자 하나만 바꿔서 앱 전체의 색상 테마를 변경할 수 있어요:
/* Default theme: blue */
:root {
--theme-hue: 210;
}
/* Green theme - just swap the hue */
[data-theme="green"] {
--theme-hue: 140;
}
/* Purple theme */
[data-theme="purple"] {
--theme-hue: 270;
}
/* All components use the same hue variable */
.button { background: hsl(var(--theme-hue), 75%, 50%); }
.link { color: hsl(var(--theme-hue), 75%, 40%); }
.badge { background: hsl(var(--theme-hue), 75%, 92%); color: hsl(var(--theme-hue), 75%, 25%); }
.focus-ring { outline-color: hsl(var(--theme-hue), 75%, 65%); }
HSL로 다크 모드 구현하기
다크 모드야말로 HSL이 진가를 발휘하는 영역이에요. 완전히 별도의 색상 팔레트를 두 벌 관리하는 대신, 동일한 색조 안에서 밝기 값만 뒤집으면 돼요:
:root {
--bg: hsl(210, 20%, 98%); /* near-white background */
--text: hsl(210, 20%, 15%); /* near-black text */
--card: hsl(210, 20%, 93%); /* slightly darker card */
}
@media (prefers-color-scheme: dark) {
:root {
--bg: hsl(210, 20%, 10%); /* flip: near-black background */
--text: hsl(210, 20%, 90%); /* flip: near-white text */
--card: hsl(210, 20%, 15%); /* slightly lighter card in dark */
}
}
색조(210)와 채도(20%)는 전혀 바뀌지 않아요. 밝기만 반전될 뿐이에요. 덕분에 다크 모드가 같은 디자인을 그대로 유지하면서 색만 반전된 느낌을 줘요. 좋은 다크 모드가 추구해야 하는 방향이 바로 이거예요.
브라우저 지원 및 호환성
HSL은 브라우저 지원이 매우 탄탄해요.
hsl()
함수는 다음 버전부터 사용 가능했어요:
- Chrome 1 (2008)
- Firefox 1 (2004)
- Safari 3.1 (2008)
- Internet Explorer 9 (2011)
- Edge 12 (2015)
쉼표 없는 최신 문법(
hsl(210 80% 50%)
)과 슬래시 알파 문법(
hsl(210 80% 50% / 0.5)
)은
CSS Color Level 4 명세
의 일부로, 2023년부터 모든 최신 브라우저에서 지원돼요. IE11 지원이 필요한 경우(요즘은 드물지만)에는 쉼표 문법을 사용하세요.
hsl()
는 사용자들이 실행하는 거의 모든 브라우저에서 동작해요. 공백으로 구분하는 최신 문법은 Chrome 90+, Firefox 89+, Safari 14.1+에서 지원되며, 전 세계 브라우저 사용량의 95% 이상을 커버해요.
HSL, RGB, HEX 형식 간 변환이 필요하거나 특정 형식만 지원하는 도구에 색상 값을 전달해야 할 때는 색상 선택 도구 를 활용해보세요.
HSL vs OKLCH - 다음은 무엇?
HSL보다 더 깊이 들어가고 싶다면 OKLCH 를 알아볼 만해요. OKLCH는 지각적으로 균일한 색 공간으로, 밝기나 채도의 수치 변화가 실제로 사람 눈에 동일한 변화로 느껴져요. HSL은 이를 완전히 보장하지 못해요.
HSL의 문제는 같은 밝기 값을 가진 두 색상이 실제 밝기 인식에서 크게 다를 수 있다는 점이에요. 예를 들어
hsl(60, 100%, 50%)
(노란색)는
hsl(240, 100%, 50%)
(파란색)보다 훨씬 밝아 보이지만, 두 색 모두 밝기는 50%예요. OKLCH는 이 문제를 보정해요.
/* HSL - same lightness, different perceived brightness */
color: hsl(60, 100%, 50%); /* yellow - looks very bright */
color: hsl(240, 100%, 50%); /* blue - looks much darker */
/* OKLCH - same lightness, actually looks the same to the eye */
color: oklch(0.75 0.18 90); /* yellow-ish */
color: oklch(0.75 0.18 260); /* blue-ish - genuinely similar perceived brightness */
OKLCH는 HSL이 제한되는 sRGB 범위를 넘어서는
와이드 색역 색상
(P3 디스플레이 색상)도 지원해요. 2024년 기준
oklch()
의 브라우저 지원은 탄탄해요: Chrome 111+, Firefox 113+, Safari 15.4+.
현재 대부분의 프로젝트에서는 HSL이 실용적인 최선이에요. 가독성이 높고, 유지보수가 쉽고, 모든 브라우저에서 지원되며, RGB에 비해 월등히 나아요. OKLCH는 수학적으로 일관된 명암비가 필요한 디자인 시스템을 구축하거나 와이드 색역 디스플레이를 대상으로 할 때 적합한 선택이에요.
팔레트를 만들면서 색상 관계를 시각적으로 탐색하고 싶다면, 색상 탐색 도구 에서 HSL 값을 직접 조작하며 색조 회전, 채도 변화, 밝기 변화가 실시간으로 어떻게 상호작용하는지 확인해보세요.
감 없이도 HSL 색상 정확하게 선택하기
색상 선택 도구로 색조, 채도, 밝기 값을 시각적으로 조정하고, HSL 색상 모델 결과를 CSS에 바로 복사해보세요. 머릿속으로 계산할 필요 없어요.
색상 선택 도구 사용해보기 →
전체를 다시 작성할 필요는 없어요. 하지만 새로 작성하는 색상 정의, 특히 CSS 커스텀 프로퍼티를 사용할 때는 HSL로 전환하는 걸 추천해요. 디자인 시스템을 구축하거나 유지보수할 때, 호버 상태를 만들 때, 다크 모드를 구현할 때 가장 큰 효과를 볼 수 있어요. 같은 프로젝트에서 RGB와 HSL을 혼용하는 것도 완전히 유효한 CSS예요. 브라우저는 두 형식을 성능 차이 없이 처리해요.
아니요, 의미 있는 성능 차이는 없어요. 브라우저는 파싱 시점에 모든 CSS 색상 형식을 내부 표현으로 변환하기 때문에,
hsl(207, 44%, 49%)
를 쓰든
rgb(70, 130, 180)
를 쓰든 렌더링 엔진은 최초 파싱 이후 동일하게 처리해요. 선택 기준은 오로지 개발자 경험과 유지보수성이에요. 런타임 성능과는 무관해요.
네, 이게 JavaScript에서 HSL이 가장 강력한 활용 사례 중 하나예요. 색조, 채도, 밝기를 별도의 숫자로 저장한 다음 색상 문자열을 동적으로 구성할 수 있어요:
element.style.color = `hsl(${hue}, ${saturation}%, ${lightness}%)`
. 이렇게 하면 같은 효과를 내기 위해 변환 계산이 필요한 RGB 채널 방식보다 애니메이션, 테마 전환, 인터랙티브 색상 컨트롤 구현이 훨씬 간단해져요.
HSL(색조, 채도, 밝기)과 HSB/HSV(색조, 채도, 명도/값)는 색조 축을 공유하지만 서로 다른 색상 모델이에요. HSL에서 밝기 50%는 순수하고 완전히 채도가 높은 색을 나타내요. HSB에서는 명도 100%가 순수한 색을 나타내요. 같은 채도와 밝기/명도 값에서도 두 모델은 서로 다른 결과를 만들어요. CSS는 HSL을 사용해요. HSB/HSV는 Photoshop이나 Figma 같은 디자인 도구에서 흔히 쓰이지만 CSS의 기본 색상 형식은 아니에요.
HEX에서 HSL로의 변환은 중간 단계로 RGB를 거쳐요. HEX 쌍을 RGB 값(0-255)으로 변환하고, 0-1로 정규화한 다음 HSL 변환 공식을 적용해요. 실제로는 대부분의 개발자가 직접 계산하지 않고 색상 선택 도구, Figma 같은 디자인 도구, 또는 브라우저 개발자 도구의 색상 선택 기능을 활용해요. 브라우저 개발자 도구에서는 색상 견본을 클릭하면 HEX, RGB, HSL 표현을 순환해서 확인할 수 있어요.
네, OKLCH는 접근성 작업에 더 신뢰할 수 있어요. 지각적으로 균일하기 때문에 밝기 채널의 동일한 수치 변화가 실제로 동일한 밝기 변화로 인식돼요. 덕분에 서로 다른 색조에서도 명암비를 예측 가능하게 유지하는 색상 팔레트를 만들기가 훨씬 쉬워요. HSL에서는 밝기 50%의 노란색이 밝기 50%의 파란색보다 훨씬 밝아 보여서 접근성에서 예상치 못한 문제가 생길 수 있어요. WCAG 명암비 준수를 위한 접근 가능한 색상 스케일을 구축할 때는 OKLCH가 더 예측 가능한 결과를 제공해요.