Mô hình màu HSL
(hue, saturation, lightness - tông màu, độ bão hòa, độ sáng) mang lại cho developer một cách làm việc với màu sắc trong CSS dễ đọc và trực quan hơn nhiều so với RGB. Thay vì phải đoán xem tổ hợp giá trị red, green, blue nào tạo ra sắc màu bạn muốn, HSL cho phép mô tả màu sắc theo cách não bộ thực sự nghĩ: chọn màu, quyết định độ tươi của nó, rồi quyết định nó sáng hay tối. Chính sự thay đổi tư duy này là lý do nhiều developer đang bỏ
rgb()
để chuyển sang
hsl()
.
Mục lục
RGB vs HSL - Sự khác biệt cốt lõi
RGB định nghĩa màu sắc bằng cách pha trộn ba kênh ánh sáng: red, green và blue, mỗi kênh có giá trị từ 0 đến 255. Vấn đề là đây là cách màn hình render pixel, không phải cách con người cảm nhận màu sắc. Nếu bạn muốn một màu xanh lam sáng hơn một chút trong RGB, bạn phải tăng cả ba kênh theo đúng tỷ lệ - không có một giá trị đơn lẻ nào để điều chỉnh.
HSL ánh xạ trực tiếp theo cách con người mô tả màu sắc trong cuộc sống:
- Hue (tông màu) - màu sắc thực tế, được biểu thị bằng độ trên vòng tròn màu 360 độ. Đỏ là 0, xanh lá là 120, xanh lam là 240.
- Saturation (độ bão hòa) - màu sắc tươi hay nhạt, từ 0% (xám thuần) đến 100% (tươi hoàn toàn).
- Lightness (độ sáng) - màu sắc sáng hay tối, từ 0% (đen) đến 100% (trắng), với 50% là màu "thuần" nhất.
Dưới đây là cùng một màu xanh lam trung tính được biểu diễn theo cả hai định dạng:
/* 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%);
Cả hai đều tạo ra màu xanh thép. Nhưng chỉ có phiên bản HSL mới cho bạn thấy điều gì đó hữu ích ngay lập tức. Hue là 207 (thiên về xanh lam), saturation ở mức vừa phải là 44%, và lightness nằm ở giữa là 49%. Bạn có thể suy luận về nó mà không cần mở color picker.
| Thuộc tính | RGB | HSL |
|---|---|---|
| Con người có thể đọc hiểu | Hiếm khi | Có |
| Làm sáng/tối màu | Điều chỉnh 3 giá trị | Chỉ điều chỉnh lightness |
| Thay đổi độ bão hòa | Tính lại cả 3 giá trị | Chỉ điều chỉnh saturation |
| Tạo bảng màu | Thử và sai | Xoay hue theo độ |
| Theming với CSS variables | Dài dòng | Gọn gàng và dễ đoán |
Cú pháp HSL trong CSS
Hàm
hsl()
trong CSS đã được hỗ trợ từ CSS3. Cú pháp hiện đại (CSS Color Level 4) cũng cho phép thêm tham số alpha thứ tư trực tiếp bên trong
hsl()
, khiến
hsla()
gần như không còn cần thiết nữa:
/* 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%);
Tất cả các trình duyệt lớn đều hỗ trợ cả hai cú pháp. Phiên bản không dùng dấu phẩy là hướng CSS đang đi, nhưng cú pháp có dấu phẩy vẫn hoạt động ở mọi nơi kể cả Internet Explorer 9+.
Tại sao HSL vượt trội trong phát triển UI
Sức mạnh thực sự của HSL bộc lộ ngay khi bạn cần tạo ra các biến thể của một màu - điều xảy ra liên tục trong công việc UI.
Xây dựng bảng màu trong vài giây
Giả sử màu thương hiệu của bạn là màu xanh lá tươi tại
hsl(140, 70%, 45%)
. Bạn cần trạng thái hover, trạng thái disabled và một nền màu nhạt. Với HSL, mỗi lần bạn chỉ cần thay đổi một giá trị:
--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 */
Hãy thử làm điều đó một cách có kiểm soát trong RGB mà không mở color picker. Thực sự rất khó vì không có trục độc lập nào để điều chỉnh.
Màu tương đồng và màu bổ sung
Vì hue là một góc độ trên vòng tròn màu, việc tạo ra các bảng màu hài hòa chỉ là phép tính số học. Màu tương đồng nằm trong phạm vi 30 độ so với nhau. Màu bổ sung cách nhau 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 */
Saturation và lightness giữ nguyên, nên các màu sắc tạo cảm giác thuộc cùng một nhóm thống nhất. Đây chính xác là cách các design system như Tailwind CSS và Material Design tạo ra bảng màu theo chương trình.
Ví dụ thực tế với CSS
CSS custom properties kết hợp với các thành phần HSL
Một trong những pattern HSL mạnh mẽ nhất là tách ba giá trị thành các CSS custom properties riêng biệt. Điều này cho phép bạn tái sử dụng chúng ở bất kỳ đâu và chỉnh từng kênh riêng lẻ ngay lập tức:
: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()
, bạn cần dùng dấu phẩy:
hsl(var(--h), var(--s), var(--l))
. Cú pháp hiện đại không dùng dấu phẩy chưa hoạt động với
var()
bên trong
hsl()
trên tất cả các trình duyệt.
Tạo dải màu tông đầy đủ
Các design system thường cần 9-10 sắc độ của một màu (như dải từ 50 đến 950 của Tailwind). Với HSL, bạn có thể tạo toàn bộ dải màu bằng cách tăng dần lightness theo các bước đều nhau trong khi giữ nguyên hue và saturation:
: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%);
}
Để tìm hiểu sâu hơn về mối quan hệ giữa các định dạng màu, hướng dẫn chuyển đổi HEX sang RGB bao quát toàn bộ bức tranh về các định dạng màu CSS, bao gồm khi nào thì nên dùng cái nào.
Trạng thái hover, theming và dark mode
Trạng thái hover và focus
HSL làm cho việc xử lý trạng thái hover trở nên đơn giản. Thay vì định nghĩa một màu hoàn toàn khác, bạn chỉ cần thay đổi lightness:
.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%);
}
Mỗi trạng thái đều rõ ràng có liên hệ với màu gốc. Đồng nghiệp đọc đoạn code này sẽ hiểu ngay mối quan hệ giữa các trạng thái.
Theming với HSL variables
HSL là nền tảng của theming CSS hiện đại. Bằng cách chỉ expose hue như một biến, bạn có thể cho phép người dùng hoặc quản trị viên thay đổi toàn bộ bảng màu của ứng dụng chỉ bằng cách thay đổi một con số:
/* 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%); }
Dark mode với HSL
Dark mode là nơi HSL thực sự bứt phá. Thay vì duy trì hai bảng màu hoàn toàn riêng biệt, bạn chỉ cần đảo ngược các giá trị lightness trong cùng một hue:
: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 */
}
}
Lưu ý rằng hue (210) và saturation (20%) không bao giờ thay đổi. Chỉ có lightness bị đảo ngược. Điều này giúp dark mode vẫn mang cảm giác cùng một thiết kế, chỉ là đảo ngược - đó chính xác là những gì dark mode tốt nên làm.
Hỗ trợ trình duyệt và khả năng tương thích
HSL có mức độ hỗ trợ trình duyệt rất tốt. Hàm
hsl()
đã có sẵn từ:
- Chrome 1 (2008)
- Firefox 1 (2004)
- Safari 3.1 (2008)
- Internet Explorer 9 (2011)
- Edge 12 (2015)
Cú pháp hiện đại không dùng dấu phẩy (
hsl(210 80% 50%)
) và cú pháp alpha với dấu gạch chéo (
hsl(210 80% 50% / 0.5)
) là một phần của
đặc tả CSS Color Level 4
và được hỗ trợ trên tất cả các trình duyệt hiện đại kể từ năm 2023. Nếu bạn cần hỗ trợ IE11 (hiếm gặp ở thời điểm này), hãy dùng cú pháp có dấu phẩy.
hsl()
với dấu phẩy hoạt động trên mọi trình duyệt mà người dùng của bạn có khả năng đang chạy. Cú pháp hiện đại phân tách bằng khoảng trắng hoạt động trên Chrome 90+, Firefox 89+ và Safari 14.1+, bao phủ hơn 95% lượng người dùng trình duyệt toàn cầu.
Bạn luôn có thể dùng công cụ color picker để chuyển đổi giữa các định dạng HSL, RGB và HEX khi bạn cần đối chiếu giá trị hoặc bàn giao màu sắc cho các công cụ chỉ chấp nhận một định dạng.
HSL vs OKLCH - Bước tiếp theo là gì?
Nếu bạn muốn đi xa hơn HSL, OKLCH là điều đáng tìm hiểu. Đây là không gian màu đồng nhất về mặt cảm nhận, có nghĩa là các bước số học bằng nhau về lightness hoặc chroma thực sự trông như nhau với mắt người - điều mà HSL không đảm bảo hoàn toàn.
Vấn đề với HSL là hai màu có cùng giá trị lightness có thể trông rất khác nhau về độ sáng cảm nhận. Ví dụ,
hsl(60, 100%, 50%)
(vàng) trông sáng hơn nhiều so với
hsl(240, 100%, 50%)
(xanh lam), dù cả hai đều có lightness 50%. OKLCH khắc phục điều này.
/* 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 cũng hỗ trợ
màu wide-gamut
(màu hiển thị P3) vượt ra ngoài phạm vi sRGB mà HSL bị giới hạn. Hỗ trợ trình duyệt cho
oklch()
rất tốt trong năm 2024: Chrome 111+, Firefox 113+, Safari 15.4+.
Với hầu hết các dự án hiện tại, HSL là điểm cân bằng thực tế: dễ đọc, dễ bảo trì, được hỗ trợ phổ quát và là sự cải thiện đáng kể so với RGB. OKLCH là lựa chọn phù hợp khi bạn đang xây dựng một design system cần tỷ lệ tương phản nhất quán về mặt toán học hoặc muốn nhắm đến màn hình wide-gamut.
Nếu bạn đang khám phá mối quan hệ màu sắc một cách trực quan trong khi xây dựng bảng màu, công cụ color explorer cho phép bạn thử nghiệm với các giá trị HSL và xem cách xoay hue, thay đổi saturation và lightness tương tác theo thời gian thực.
Chọn màu HSL không cần đoán mò
Công cụ color picker của chúng tôi cho phép bạn điều chỉnh trực quan các giá trị hue, saturation và lightness, rồi sao chép trực tiếp kết quả màu HSL vào CSS - không cần tính toán trong đầu.
Dùng thử Color Picker →
Bạn không cần phải viết lại toàn bộ, nhưng nên chuyển sang HSL cho mọi định nghĩa màu mới, đặc biệt khi dùng CSS custom properties. Lợi ích lớn nhất đến khi bạn đang xây dựng hoặc bảo trì một design system, tạo trạng thái hover, hoặc triển khai dark mode. Việc kết hợp RGB và HSL trong cùng một dự án là CSS hoàn toàn hợp lệ - trình duyệt xử lý cả hai mà không có bất kỳ sự khác biệt hiệu năng nào.
Không, không có sự khác biệt hiệu năng đáng kể nào. Trình duyệt chuyển đổi tất cả các định dạng màu CSS sang biểu diễn nội bộ tại thời điểm parse, vì vậy dù bạn viết
hsl(207, 44%, 49%)
hay
rgb(70, 130, 180)
, rendering engine đều xử lý chúng như nhau sau bước parse ban đầu đó. Sự lựa chọn hoàn toàn về trải nghiệm developer và khả năng bảo trì, không phải hiệu năng runtime.
Có, và đây là một trong những trường hợp sử dụng mạnh nhất của HSL trong JavaScript. Bạn có thể lưu hue, saturation và lightness dưới dạng các số riêng biệt, rồi xây dựng chuỗi màu động:
element.style.color = `hsl(${hue}, ${saturation}%, ${lightness}%)`
. Điều này giúp animation, chuyển đổi theme và các điều khiển màu sắc tương tác đơn giản hơn nhiều so với làm việc với các kênh RGB, nơi bạn cần toán học chuyển đổi để đạt được hiệu ứng tương tự.
HSL (hue, saturation, lightness) và HSB/HSV (hue, saturation, brightness/value) là các mô hình màu khác nhau dù chúng chia sẻ trục hue. Trong HSL, lightness 50% cho bạn màu thuần, bão hòa hoàn toàn. Trong HSB, brightness 100% cho bạn màu thuần. Hai mô hình tạo ra kết quả khác nhau với cùng giá trị saturation và brightness/lightness. CSS dùng HSL - HSB/HSV phổ biến trong các công cụ thiết kế như Photoshop và Figma nhưng không phải định dạng CSS gốc.
Việc chuyển đổi từ HEX sang HSL đi qua bước trung gian RGB: trước tiên chuyển các cặp HEX thành giá trị RGB (0-255), chuẩn hóa về 0-1, rồi áp dụng công thức chuyển đổi HSL. Trong thực tế, hầu hết developer dùng công cụ color picker, công cụ thiết kế như Figma, hoặc color picker trong DevTools của trình duyệt để làm điều này ngay lập tức thay vì tính tay. DevTools của trình duyệt cho phép bạn nhấp vào bất kỳ ô màu nào và chuyển đổi qua lại giữa các biểu diễn HEX, RGB và HSL.
Có, OKLCH đáng tin cậy hơn cho công việc liên quan đến khả năng tiếp cận vì nó đồng nhất về mặt cảm nhận - các bước bằng nhau trong kênh lightness tương ứng với các thay đổi độ sáng cảm nhận bằng nhau. Điều này giúp dễ dàng xây dựng bảng màu với tỷ lệ tương phản có thể dự đoán được trên các hue khác nhau. Với HSL, vàng ở lightness 50% trông sáng hơn nhiều so với xanh lam ở lightness 50%, điều này có thể gây ra những bất ngờ về khả năng tiếp cận. Để tuân thủ tương phản WCAG, OKLCH cho bạn kết quả dễ đoán hơn khi xây dựng bảng màu dễ tiếp cận.