OKLCH là gì
(jakub.kr)- OKLCH là mô hình màu hiện đại được thiết kế phù hợp với nhận thức thị giác của con người, với đặc tính sự thay đổi về độ sáng, độ bão hòa và màu sắc giữa các màu được cảm nhận một cách đồng đều, tức là một mô hình màu đồng nhất theo cảm nhận
- Cấu trúc gồm Lightness (độ sáng), Chroma (độ bão hòa), Hue (màu sắc), cho phép tạo bảng màu nhất quán tốt hơn so với các mô hình trước đây
- Chỉ cần thay đổi Hue trong khi giữ nguyên cùng độ sáng và độ bão hòa là có thể tạo ra bảng màu đồng đều, rất hữu ích cho thiết kế UI
- So với sRGB/HSL, nó cung cấp sự thay đổi sáng tối dễ dự đoán và gradient đồng đều, nhưng trong một số trường hợp có thể tạo ra màu ngoài ý muốn
- Trên các màn hình hiện đại như Display-P3, có thể biểu diễn dải màu rộng hơn; đồng thời được hỗ trợ qua CSS Color 4 trên các trình duyệt mới và cũng có xử lý fallback sRGB, nên đang dần trở thành một phần của tiêu chuẩn web
Giới thiệu mô hình màu OKLCH
- OKLCH là mô hình màu hiện đại được phát triển với mục tiêu đồng nhất theo cảm nhận (perceptually uniform)
- Mô hình này hoạt động gần hơn với cách con người thực sự nhận biết màu sắc, nên việc xử lý màu sắc trong thiết kế số và phát triển frontend trở nên thuận tiện hơn nhiều
Khái niệm cơ bản về mô hình màu
- Mô hình màu là hệ thống dùng để định nghĩa và biểu diễn màu sắc bằng toán học
- Ví dụ về các mô hình thường dùng: RGB, HSL, LCH, OKLCH, LAB, XYZ
- Mỗi mô hình quyết định mức độ dễ dàng trong việc biểu diễn và thao tác màu sắc
Ví dụ về cách biểu diễn màu
- oklch(0.55 0.18 260)
- hsl(220 100% 50%)
- rgb(0, 128, 255)
- lch(60% 60 260)
- lab(50 -10 -50)
- color(xyz 0.18 0.19 0.6)
- #1E90FF
Gamut (phạm vi không gian màu)
- Gamut là toàn bộ phạm vi màu mà mô hình màu đó có thể biểu diễn
- Các gamut tiêu biểu: sRGB (mặc định của web), Display-P3 (được hỗ trợ trên thiết bị hiện đại)
- Không gian màu ngoài phạm vi gamut còn có nhiều thuộc tính khác như white point, transfer function
Cấu trúc của OKLCH
Cả OKLCH và LCH đều gồm ba giá trị: Lightness, Chroma, Hue
OKLCH dựa trên không gian màu OKLab
- Lightness (độ sáng/độ chói): biểu diễn từ 0~1 hoặc 0%~100%, đảm bảo sự thay đổi độ sáng đồng đều
- Chroma (độ bão hòa): cường độ của màu, tương tự Saturation (độ bão hòa) trong HSL
- Hue (màu sắc): biểu diễn màu theo góc từ 0~360 độ
Ưu điểm và ứng dụng của OKLCH
-
Độ sáng nhất quán
- Trong OKLCH, nếu chỉ thay đổi hue với cùng độ sáng và độ bão hòa, thì mọi màu sẽ được cảm nhận với độ sáng tương tự nhau
- Với sRGB hay HSL truyền thống, độ sáng hoặc độ bão hòa có thể trông không nhất quán giữa các màu
- Vì vậy, OKLCH giúp tạo bảng màu đồng nhất theo cảm nhận dễ dàng hơn
-
Các mức sáng tối của màu dễ dự đoán
- Trong OKLCH, khi thay đổi độ sáng, bạn có thể tạo ra nhiều cấp độ màu mà không làm thay đổi hue (màu sắc) hay chroma (độ bão hòa)
- Với HSL hay các mô hình tương tự, khi độ sáng thay đổi thường xảy ra hiện tượng trôi sắc độ
- OKLCH cho phép tạo các thang màu sáng tối nhất quán chỉ bằng cách điều chỉnh độ sáng
-
Cách xử lý gradient
- Trong sRGB, gradient là nội suy giữa các giá trị đỏ, lục, lam, nên điểm trung gian có thể bị xỉn hoặc thay đổi độ sáng mạnh
- OKLCH nội suy theo các trục Lightness, Chroma, Hue, nên có thể tạo gradient tự nhiên hơn
- Tuy nhiên, vì Hue có cấu trúc vòng tròn, có thể phát sinh biến đổi màu ngoài dự kiến
- Để tránh điều này, có thể nội suy tuyến tính trong OKLab để có kết quả dễ dự đoán hơn
Hỗ trợ không gian màu
- sRGB không thể bao phủ hết một phần dải màu rộng mà các màn hình hiện đại có thể hiển thị
- Khi dùng OKLCH, các thiết bị hỗ trợ dải màu rộng như Display-P3 có thể thể hiện màu sắc sống động hơn
- Trên các thiết bị chỉ hỗ trợ sRGB, màu sẽ được ánh xạ sang màu gần giống nhất có thể
Giá trị Chroma (độ bão hòa) tối đa
- OKLCH có thể chỉ định về mặt toán học cả những màu nằm ngoài phạm vi mà màn hình thực tế có thể hiển thị
- Ví dụ, giá trị chroma quá lớn như
oklch(0.7 0.4 40)sẽ không thể hiển thị thực tế và bị clipping về màu gần nhất - Cần hiểu khái niệm chroma tối đa và đặt giá trị phù hợp tùy theo sắc độ, độ sáng và không gian màu được chọn (sRGB, Display-P3)
Hỗ trợ trình duyệt và fallback
- Màu OKLCH được giới thiệu trong CSS Color Module Level 4 và hiện đã được phần lớn trình duyệt hiện đại hỗ trợ
- Trên trình duyệt cũ có thể không được hỗ trợ, nên có thể dùng chỉ thị CSS @supports để đặt giá trị fallback
@layer base { :root { /* sRGB hex */ --color-gray-100: #fcfcfc; --color-gray-200: #fafafa; --color-gray-300: #f4f4f4; @supports (color: oklch(0 0 0)) { /* OKLCH */ --color-gray-100: oklch(0.991 0 0); --color-gray-200: oklch(0.982 0 0); --color-gray-300: oklch(0.955 0 0); } } } - Trên trình duyệt được hỗ trợ sẽ áp dụng OKLCH, còn trên trình duyệt không hỗ trợ sẽ áp dụng màu sRGB (hex)
Công cụ oklch.fyi
- oklch.fyi là công cụ web cung cấp các tính năng liên quan đến OKLCH như tạo bảng màu OKLCH, chuyển đổi biến CSS, v.v.
- Công cụ này giúp việc ứng dụng màu OKLCH trong thiết kế hệ thống và phát triển theme trở nên dễ dàng hơn
1 bình luận
Ý kiến Hacker News
Tôi thấy nghi ngờ về tính năng “Better Gradients”. OKLCH là một không gian cực tọa độ, trong đó Hue đóng vai trò là góc. Khi nội suy màu giữa hai điểm khác nhau, đường đi sẽ men theo rìa của vòng tròn. Ví dụ, nếu dùng
linear-gradient(in oklch, #f0f, #0f0)thì trong quá trình chuyển từ xanh lá sang tím, màu sẽ dễ dàng đi ra ngoài dải màu một cách rõ rệt. Nếu đi vòng theo hướng còn lại trên vòng tròn, nhưlinear-gradient(in oklch longer hue, #f0f, #0f0), nó sẽ đi qua cyan hoặc aqua. Những đường đi như vậy cho thấy không gian màu dựa trên cảm nhận này xử lý phần rìa của sRGB hay vùng màu con người có thể cảm nhận được, tức gamut, theo cách thật sự bất tiện. Thực tế, chỉ cần chênh lệch giá trị rất nhỏ là màu đã vượt khỏi phạm vi. Có nhiều thuật toán để xử lý việc này, nhưng phải đánh đổi tính đồng đều theo cảm nhận. Chẳng hạn, màu đỏ trên gradient sẽ tối đi một cách bất thường. Nếu bạn muốn gradient đẹp hơn và coi trọng tính đồng đều theo cảm nhận, thì nội suy Oklab thực ra mới nên là mặc định. Oklab nội suy theo đường thẳng cắt ngang vòng tròn, và nếu cần thì còn đi qua cả màu xám (linear-gradient(in oklab, #f0f, #0f0)). Cách này cũng loại bỏ hiện tượng tối đi thường thấy khi nội suy sRGB, đồng thời tạo ra gradient tự nhiên từ magenta sang lime. Nhân tiện, Tailwind v4 từng dùng Oklch thay cho sRGB ở bản beta, nhưng đến bản phát hành chính thức thì chọn Oklab làm mặc định an toàn hơnTôi nghĩ cách trình duyệt nội suy màu trong sRGB thực ra gần như là một lỗi. sRGB là kiểu mã hóa theo thang log, nên theo đặc tả ban đầu, không nên nội suy màu trực tiếp trong sRGB mà phải chuyển sang linear RGB rồi mới nội suy
Bài viết này đã được chỉnh sửa nên bạn có thể bỏ qua bình luận của tôi. Dù vậy, tôi vẫn đồng ý rằng nên dùng nội suy Oklab làm mặc định. Ngay trong bài cũng nói về “gradient tốt hơn”, rằng hue của OKLCH có tính tuần hoàn nên có thể tạo ra đường đi không như mong đợi. Để tránh vấn đề này, nhiều công cụ dùng OKLAB, và Oklab cho kết quả nhất quán với đường đi thẳng
Thực ra CIE LAB cũng làm được vai trò tương tự và đã tồn tại như một tiêu chuẩn (Wikipedia CIE LAB)
Tài liệu xem xét của W3C
Cảm ơn vì lời giải thích rất hữu ích. Tôi là người viết bài này. Tôi sẽ chỉnh sửa nội dung để giải thích cho rõ hơn
Trường hợp tạo gradient bằng hai màu nằm ở hai phía đối diện của phổ màu là một ví dụ khá cực đoan. Cũng không có đáp án đúng tuyệt đối cho việc nó nên trông như thế nào, và tôi nghĩ trong thiết kế thực tế hiếm khi cần những gradient như vậy. Thông thường khi dùng gradient trong thiết kế, người ta sẽ tự chọn màu trung gian
Với OKLCH, tôi thấy oklch.com khá hữu ích để xây dựng trực giác. Tuy nhiên cần lưu ý rằng giá trị hue khác với hue trong HSL, và mức chroma tối đa cũng thay đổi theo hue và lightness. Đây không phải bug mà phản ánh đặc tính của mắt người và màn hình hiển thị. Khác với OKLCH, HSL luôn có cùng một giá trị tối đa, nhưng ý nghĩa màu sắc lại không nhất quán. Điểm hay của OKLCH trong CSS là có thể thao tác dưới dạng công thức. Ví dụ có thể viết
oklch(from var(--accent) calc(l + .1) c h). Nhưng để dùng công thức hiệu quả trong thực tế, bạn vẫn cần hiểu lý thuyết màu hoặc phải thử nghiệm. Chẳng hạn tôi từng nghĩ bóng đổ chỉ cần thay lightness là đủ, nhưng thực tế hue cũng cần thay đổi. Không phải lúc nào gradient OKLCH cũng là tốt nhất. Khi dùng các hue gần nhau thì màu có vẻ đồng đều hơn, nhưng nếu còn quan tâm đến việc ánh sáng thực sự trộn với nhau như thế nào trong vật lý, thì bạn sẽ cần không gian màu XYZ. Có thể tham khảo tài liệu color-mix của MDN. Nhân tiện, “ok” thực sự chỉ đến từ chính từ OK. Về mặt ý nghĩa, nó xuất phát từ việc LCH trước đó có vấn đề, tức là không “OK”Bạn nói điểm hay là có thể dùng công thức trong OKLCH của CSS, nhưng thực ra thao tác màu tương đối dùng được trong mọi không gian màu của CSS. Ví dụ có thể dùng
background-color: rgb(from var(--base-color) calc(r - 76.5) g calc(b + 76.5));Nhờ OKLCH và màu tương đối, tôi đã giảm được rất nhiều số lượng màu phải hardcode trong stylesheet
Ví dụ về biến CSS
Một số điểm phê bình đã được nhắc đến rồi, nhưng tôi vẫn thấy đây là một bài khá ổn để giới thiệu về OKLCH và cách áp dụng trong CSS. Nhân tiện, tôi lại thắc mắc về xu hướng gần đây là các bài blog không ghi ngày tháng. Đặc biệt, câu “OKLCH là một mô hình màu mới” rồi sẽ nhanh chóng lỗi thời trong tương lai. Trên trang chính chỉ ghi “tháng 8 năm 2025”, nên cảm giác như họ cố tình tránh ghi ngày cụ thể
Trang liên quan
Tôi không giải thích thật chính xác được, nhưng tôi thấy bài viết không có ngày tháng là một vấn đề nghiêm trọng. Tôi không biết đây có phải xu hướng gần đây hay không, nhưng nếu không có ngày thì rất dễ nhầm là bài cũ. Thỉnh thoảng tôi phải đoán năm của bài qua timestamp còn sót lại trong bình luận, nhưng lại có nhiều blog thậm chí không hỗ trợ bình luận, khiến tôi chẳng còn muốn quay lại. (Trên trang chính của tác giả có viết “không ám ảnh chi tiết”, nên cũng khá mỉa mai khi họ lại chỉ chăm chút phần thẩm mỹ thiết kế mà bỏ quên tính hữu dụng)
Khi bài viết không có ngày, tôi thường thử xem header
Last-Modifiedkhi lấy tài liệu HTML qua HTTP. Nhưng nhiều khi tác giả vốn không quan tâm đến ngày tháng. Ngay từ cái tên blog cũng cho thấy bản chất là [web]-log, nơi timestamp là yếu tố cốt lõi, nhưng có vẻ họ không hiểu điều đó. Nhân tiện, giá trịLast-Modifiedbiểu thị thời điểm chỉnh sửa cuối cùng của tài nguyên đó (HTML). Nếu server không cấu hình cache và backend render lại mỗi lần, ngày này sẽ luôn được cập nhậtVí dụ về vấn đề này
Chủ yếu là một mẹo SEO để tránh nội dung cũ bị công cụ tìm kiếm hạ hạng. Đúng là một trò khá phiền
Là vì Google và SEO
Bài viết nói màu OKLCH cho màu xanh dương nhất quán hơn so với HSL, nhưng thực tế khi tăng độ sáng trong OKLCH thì màu lại dịch mạnh về phía xanh lá. Việc giữ perceptual intensity ổn định rõ ràng là một ưu điểm, nhưng tôi thấy hiệu ứng được tuyên bố ở đây hơi bị phóng đại
Nhìn vào biểu đồ hue của màu này thì sẽ hiểu lý do
Biểu đồ màu OKLCH
Khi tăng độ sáng, nó vượt qua giới hạn của dải hue ở màu đó, nên do giới hạn của màu xanh sáng mà màn hình có thể tái tạo được, màu sẽ dịch sang phía cyan. Khi điều chỉnh độ sáng trong OKLCH, thứ được giữ cố định không phải hue mà là saturation. Hiệu ứng này có đẹp hay không là vấn đề gu thẩm mỹ, nhưng sau thời gian dài chỉ dùng web color ít bão hòa với hue cố định, việc “có thể chọn điểm đánh đổi theo hướng nào” lại thấy khá mới mẻ
Thảo luận Hacker News liên quan
Gần đây giới khoa học cũng đã phát minh ra LED xanh dương đậm hơn, nên tôi kỳ vọng rằng trong 10~20 năm tới, nếu có công nghệ thay thế Display P3, ta có thể thể hiện gradient xanh dương chính xác hơn mà không bị dịch sang cyan như thế này. Từ giờ đến lúc đó, thứ trông đẹp về mặt thiết kế vẫn là đáp án đúng.
Nhân tiện, tôi nghĩ trong tương lai khi thiết kế không gian màu, thay vì bắt buộc phải chọn nhị nguyên giữa Hue và Saturation, có thể giữ Saturation bất biến đến giới hạn của màn hình rồi từ điểm đó chuyển dần sang giữ Hue bất biến. Nhưng điều này rất khó do các ràng buộc của color profile (IDCv4). Dù vậy, nó có vẻ thú vị như một target thử nghiệm cho DisplayCAL
Trên màn hình của tôi thì ví dụ đó hoàn toàn không thấy hiện tượng lệch sang xanh lá. Không biết có phải màn hình của bạn chưa được cân chỉnh đúng không
Tôi đồng ý. Màu đổi hẳn từ xanh dương sang cyan. Nếu OKLCH đúng là được triển khai như vậy thì tôi chẳng bao giờ muốn dùng. Có vẻ có vấn đề nghiêm trọng trong cách tính hue. HSL/HSV có vấn đề về lightness theo cảm nhận, nhưng hue thì luôn ổn định nên không cần hiệu chỉnh
Tôi không rành khoa học màu và đây có thể chỉ là ý kiến chủ quan, nhưng ở đầu bên phải của dải OKLCH, tệ nhất tôi vẫn cảm thấy đó là blue-green hoặc đơn giản là light blue. Trong khi đó, hai màu sáng nhất của HSL lại không hề giống blue; màu áp chót bên phải giống light purple hơn, còn màu ngoài cùng bên phải thì gần như màu xám. Phần chú thích nói phía tối của HSL bị grayish, nhưng thực tế ở vị trí ngoài cùng bên trái, cả OKLCH và HSL đều vẫn cho cảm giác là màu xanh. Nếu đo bằng macOS Digital Color Meter thì ở đầu ngoài cùng bên phải, giá trị green của OKLCH và HSL gần như giống nhau (226 và 227, còn trong sRGB là 228 và 227)
Tôi gợi ý một bài tốt hơn về chủ đề này
OKLCH in CSS: Why quit RGB, HSL của Evil Martians
Công cụ chuyển đổi OKLCH để thử
Thảo luận Hacker News trước đó (6 tháng trước, 30 bình luận)
OKLCH được xây dựng dựa trên OKLab (một không gian màu đồng đều theo cảm nhận), và là mô hình điều chỉnh Lightness (độ sáng), Chroma (độ bão hòa), Hue (sắc độ). “OK” là tên gọi lấy từ việc người tạo ra nó từng trả lời rằng nó “hoạt động khá ổn”
Tôi nghĩ khi làm việc với màu sắc và văn bản/logo thì cũng nhất định phải cân nhắc độ tương phản và khả năng đọc
APCA Contrast
Kiểm tra độ tương phản (WCAG 2)
Ngoài ra còn có nhiều công cụ khác
Trong đầu tôi, cái tên OKLCH tự nhiên được hiểu thành "Oklachroma"
Có một bài blog đầu tiên giới thiệu không gian màu OKLab, khá thú vị nếu nhìn ở góc độ lịch sử
Bài gốc về OKLab
Tôi thắc mắc vì sao công thức chuyển đổi sang không gian màu OKLCH lại không được tài liệu hóa rõ ràng. Tìm Google thì chỉ thấy một Gist[0], còn Oklab thì có trang Wikipedia[1]
Ví dụ công thức chuyển đổi trong Gist
Wikipedia về Oklab
Cốt lõi của việc chuyển đổi nằm ở ma trận giữa Oklab và sRGB. Bản thân việc chuyển đổi giữa OKLab và OKLCH chỉ là phép đổi hệ tọa độ, và Wikipedia cũng có nói đến
OKLCH và OKLab là cùng một không gian màu. Chỉ khác cách biểu diễn bằng tọa độ trực giao (OKLab) so với tọa độ cực (OKLCH)