Tổng quan cơ bản về cách thiết lập bảng phối màu động và có thể định cấu hình
Trong bài đăng này, tôi muốn chia sẻ suy nghĩ về cách quản lý nhiều bảng phối màu trong CSS. Dùng thử bản minh hoạ.
Nếu bạn thích xem video, hãy xem phiên bản video của bài đăng này trên YouTube:
Tổng quan
Chúng ta sẽ xây dựng một hệ thống màu sắc dễ tiếp cận bằng các thuộc tính tuỳ chỉnh và calc()
để tạo một trang web thích ứng với lựa chọn ưu tiên của người dùng trong khi vẫn giữ cho trải nghiệm tạo nội dung ở mức tối thiểu. Chúng ta bắt đầu bằng một màu sắc cơ bản của thương hiệu và xây dựng một hệ thống biến thể từ màu sắc đó: 2 màu văn bản, 4 màu nền và một bóng phù hợp.
Hướng dẫn này bắt đầu bằng cách xác định tất cả màu sắc cho từng bảng phối màu. Mã này chỉ được dùng để thay đổi trang ở cuối cùng.
Thương hiệu
Thường thì màu sắc của thương hiệu đã được thiết lập và được phân phối dưới dạng hex hoặc rgb. Thử thách về giao diện người dùng đồ hoạ này có màu cơ bản của thương hiệu là #0af
. Trước tiên, đối với hệ thống màu này, giá trị hex cần được chuyển đổi thành hsl.
* {
--brand: #0af;
--brand: hsl(200 100% 50%);
}
Để bật khái niệm làm tối hoặc làm sáng màu thương hiệu, chẳng hạn như 20%, 3 kênh của giá trị màu hsl cần được trích xuất vào các thuộc tính tuỳ chỉnh riêng, như sau:
* {
--brand-hue: 200;
--brand-saturation: 100%;
--brand-lightness: 50%;
}
CSS có thể thực hiện phép tính trên các thuộc tính màu đó, ví dụ: calc(var(--brand-lightness) -
20%)
để giảm 20% giá trị độ sáng. Đây là nền tảng để xây dựng bảng phối màu vì CSS có thể giữ tất cả các màu trong cùng một gia đình màu bằng cách điều chỉnh độ bão hoà và độ sáng hsl.
Giao diện sáng
Mỗi biến thể màu sẽ được đánh dấu bằng giao diện phù hợp, trong trường hợp này, mỗi biến thể sẽ được thêm vào -light
.
Thương hiệu
Bắt đầu với màu sắc thương hiệu, màu sắc này được tạo lại bằng cách gói các thuộc tính tuỳ chỉnh --brand-hue
, --brand-saturation
và --brand-lightness
bên trong dấu ngoặc đơn của hàm hsl ()
mà không cần tính toán:
* {
--brand-light: hsl(var(--brand-hue) var(--brand-saturation) var(--brand-lightness));
}
Màu văn bản
Tiếp theo, bảng phối màu cần có màu văn bản. Trong giao diện sáng, văn bản phải rất tối. Hãy lưu ý độ sáng của các màu sau đây rất thấp, dưới 50%.
* {
--text1-light: hsl(var(--brand-hue) var(--brand-saturation) 10%);
--text2-light: hsl(var(--brand-hue) 30% 30%);
}
--text1-light
, vì màu này rất tối ở độ sáng 10%, nên giữ độ bão hoà cao 100% để màu sắc thương hiệu vẫn có thể lấp ló trong màu xanh dương đậm.
--text2-light
, màu này không tối như màu thứ nhất, điều này rất tốt vì đây là màu phụ và cũng ít bão hoà hơn nhiều.
Màu cho vùng hiển thị
Màu sắc của bề mặt là nền, đường viền và các bề mặt trang trí khác mà văn bản nằm trên hoặc bên trong. Trong giao diện sáng, đây là các màu sáng, trái ngược với màu văn bản tối. Để tạo màu sáng bằng hsl, chúng ta sẽ sử dụng các giá trị phần trăm cao hơn trong giá trị độ sáng thứ ba. Chúng ta cũng sẽ giảm độ bão hoà để màu xám nhạt không bị quá đậm.
* {
--surface1-light: hsl(var(--brand-hue) 25% 90%);
--surface2-light: hsl(var(--brand-hue) 20% 99%);
--surface3-light: hsl(var(--brand-hue) 20% 92%);
--surface4-light: hsl(var(--brand-hue) 20% 85%);
}
4 màu sắc bề mặt đã được tạo vì màu trang trí thường cần nhiều biến thể hơn, cho các khoảnh khắc tương tác như :focus
hoặc :hover
hoặc để tạo giao diện của các lớp giấy. Trong những trường hợp này, bạn nên chuyển đổi --surface2-light
khi di chuột sang --surface3-light
, vì vậy, khi di chuột, độ tương phản sẽ tăng lên (độ sáng 99% thành độ sáng 92%; làm cho màu tối hơn).
Bóng
Bóng trong bảng phối màu là một yếu tố vượt trội, nhưng cũng mang lại hiệu ứng chân thực và giúp hiệu ứng này nổi bật so với bóng dựa trên màu đen không thực tế. Để làm điều này, màu của bóng sẽ sử dụng thuộc tính tuỳ chỉnh sắc độ, hơi bão hoà với sắc độ nhưng vẫn rất tối. Về cơ bản, hãy tạo một bóng rất tối, hơi xanh.
* {
--surface-shadow-light: var(--brand-hue) 10% 20%;
--shadow-strength-light: .02;
}
--surface-shadow-light
không được gói trong hàm hsl. Lý do là giá trị --shadow-strength
sẽ được kết hợp để tạo độ mờ và CSS cần các phần này để thực hiện phép tính. Chuyển đến phần bóng đổ hình tròn để tìm hiểu thêm.
Tất cả màu sáng
Bạn không cần phải tìm kiếm để biết cách tạo màu sáng, tất cả màu sắc đều ở cùng một nơi trong CSS.
* {
--brand-light: hsl(var(--brand-hue) var(--brand-saturation) var(--brand-lightness));
--text1-light: hsl(var(--brand-hue) var(--brand-saturation) 10%);
--text2-light: hsl(var(--brand-hue) 30% 30%);
--surface1-light: hsl(var(--brand-hue) 25% 90%);
--surface2-light: hsl(var(--brand-hue) 20% 99%);
--surface3-light: hsl(var(--brand-hue) 20% 92%);
--surface4-light: hsl(var(--brand-hue) 20% 85%);
--surface-shadow-light: var(--brand-hue) 10% calc(var(--brand-lightness) / 5);
--shadow-strength-light: .02;
}
Giao diện tối
Hầu hết các thương hiệu không bắt đầu bằng giao diện tối, mà là một biến thể của giao diện chính, thường là sáng hơn. Mặt khác, người dùng thường chọn giao diện tối cho nhiều ngữ cảnh, chẳng hạn như ban đêm. Những yếu tố này đã khiến tôi lưu ý đến hai điều sau đây khi thiết kế giao diện tối:
- Người dùng thường ở trong bóng tối khi sử dụng giao diện này, vì vậy, hãy kiểm thử trong bóng tối.
- Màu sắc nên giảm độ bão hoà để không bị rung trên màn hình do quá đậm.
Thương hiệu
Giao diện sáng sử dụng 3 giá trị kênh màu hsl của thương hiệu mà không thay đổi, còn giao diện tối thì không. Độ bão hoà giảm một nửa và độ sáng giảm tương đối 50%.
* {
--brand-dark: hsl(
var(--brand-hue)
calc(var(--brand-saturation) / 2)
calc(var(--brand-lightness) / 1.5)
);
}
Màu văn bản
Trong giao diện tối, màu văn bản phải sáng. Các màu sau đây có giá trị độ sáng cao, khiến chúng gần với màu trắng hơn.
* {
--text1-dark: hsl(var(--brand-hue) 15% 85%);
--text2-dark: hsl(var(--brand-hue) 5% 65%);
}
Màu cho vùng hiển thị
Trong giao diện tối, màu bề mặt phải là màu tối. Các màu sau đây có độ sáng và độ bão hoà thấp, trong đó bề mặt 1 là tối nhất ở mức 10%.
* {
--surface1-dark: hsl(var(--brand-hue) 10% 10%);
--surface2-dark: hsl(var(--brand-hue) 10% 15%);
--surface3-dark: hsl(var(--brand-hue) 5% 20%);
--surface4-dark: hsl(var(--brand-hue) 5% 25%);
}
Bóng
Trong giao diện tối, rất khó để nhìn thấy bóng đổ. Điều này cũng dễ hiểu vì khó làm tối một đối tượng đã khá tối. Đây là lúc --shadow-strength-dark
trở nên cực kỳ hữu ích vì cho phép chúng ta làm tối bóng bằng cách thay đổi một biến.
* {
--surface-shadow-dark: var(--brand-hue) 50% 3%;
--shadow-strength-dark: .8;
}
Ngoài ra, hãy xem độ bão hoà trong bóng đó. Bạn có nhận thấy màu sắc khi nhìn vào giao diện không? Hãy thử xoá độ bão hoà khỏi devtools, bạn thích cái nào hơn?!
Tất cả màu tối
* {
--brand-dark: hsl(var(--brand-hue) calc(var(--brand-saturation) / 2) calc(var(--brand-lightness) / 1.5));
--text1-dark: hsl(var(--brand-hue) 15% 85%);
--text2-dark: hsl(var(--brand-hue) 5% 65%);
--surface1-dark: hsl(var(--brand-hue) 10% 10%);
--surface2-dark: hsl(var(--brand-hue) 10% 15%);
--surface3-dark: hsl(var(--brand-hue) 5% 20%);
--surface4-dark: hsl(var(--brand-hue) 5% 25%);
--surface-shadow-dark: var(--brand-hue) 50% 3%;
--shadow-strength-dark: .8;
}
Giao diện tối
Bảng phối màu này chủ yếu là về việc điều phối độ sáng và độ bão hoà. Màu sắc phải có đủ độ bão hoà để vẫn có thể nhìn thấy sắc độ, nhưng cũng chỉ vừa đủ để vượt qua điểm tương phản vì dù sao thì màu sắc này cũng được thiết kế để có độ tương phản thấp và mờ.
Thương hiệu
* {
--brand-dim: hsl(
var(--brand-hue)
calc(var(--brand-saturation) / 1.25)
calc(var(--brand-lightness) / 1.25)
);
}
Màu văn bản
* {
--text1-dim: hsl(var(--brand-hue) 15% 75%);
--text2-dim: hsl(var(--brand-hue) 10% 61%);
}
Màu cho vùng hiển thị
* {
--surface1-dim: hsl(var(--brand-hue) 10% 20%);
--surface2-dim: hsl(var(--brand-hue) 10% 25%);
--surface3-dim: hsl(var(--brand-hue) 5% 30%);
--surface4-dim: hsl(var(--brand-hue) 5% 35%);
}
Bóng
* {
--surface-shadow-dim: var(--brand-hue) 30% 13%;
--shadow-strength-dim: .2;
}
Làm mờ tất cả màu
* {
--brand-dim: hsl(var(--brand-hue) calc(var(--brand-saturation) / 1.25) calc(var(--brand-lightness) / 1.25));
--text1-dim: hsl(var(--brand-hue) 15% 75%);
--text2-dim: hsl(var(--brand-hue) 10% 61%);
--surface1-dim: hsl(var(--brand-hue) 10% 20%);
--surface2-dim: hsl(var(--brand-hue) 10% 25%);
--surface3-dim: hsl(var(--brand-hue) 5% 30%);
--surface4-dim: hsl(var(--brand-hue) 5% 35%);
--surface-shadow-dim: var(--brand-hue) 30% 13%;
--shadow-strength-dim: .2;
}
Màu sắc hỗ trợ tiếp cận
Lưu ý độ sáng thấp nhất trong nhóm màu văn bản tối là 65% và độ sáng cao nhất trong các bề mặt tối là 25%. Đó là 40% độ sáng giữa các thành phần. Trong giao diện sáng, có 55% khoảng thở trong giao diện sáng. Việc duy trì sự khác biệt về độ sáng giữa màu văn bản và màu nền ở mức khoảng 40-50% có thể giúp duy trì độ tương phản màu cao, đồng thời là một đòn bẩy tinh tế để điều chỉnh trong trường hợp điểm số thấp.
Tôi gọi đó là "bump bump til ya pass" (nhấn cho đến khi bạn vượt qua), đó là hoạt động tương tác của việc nhấn vào giá trị độ sáng cho đến khi một công cụ cho thấy tôi đang vượt qua.
Mỗi giao diện được tạo trong thử thách này đều đạt điểm tương phản. Bảng phối màu tối có độ tương phản thấp nhất trong số các bảng phối màu, nhưng vẫn đáp ứng các yêu cầu tối thiểu. Để giúp những người khác trong nhóm sử dụng màu tương phản tốt, bạn nên tạo một tên lớp kết hợp màu nền với màu văn bản dễ tiếp cận.
.surface1 {
background-color: var(--surface1);
color: var(--text2);
}
.surface2 {
background-color: var(--surface2);
color: var(--text2);
}
.surface3 {
background-color: var(--surface3);
color: var(--text1);
}
.surface4 {
background-color: var(--surface4);
color: var(--text1);
}
Rad Shadow
Các giao diện sử dụng một lớp tiện ích có tên là .rad-shadow
. Bóng này được tạo bằng công cụ Smooth Shadow (Bóng mượt) mà tôi rất cảm ơn. Tôi đã lấy đoạn mã được tạo và tuỳ chỉnh đoạn mã đó bằng màu sắc và tính toán độ mờ của riêng mình. Lý do là để tạo một bóng đổ mà tôi có thể điều chỉnh trong mỗi bảng phối màu.
Để thực hiện việc này, tôi đã tạo 2 biến cho mỗi bảng phối màu để điều chỉnh, một màu bóng và độ đậm của bóng. Màu sắc dùng để điều chỉnh độ bão hoà và độ tối, còn độ đậm là cách dễ dàng để tăng cường độ bóng khi đó là bảng phối màu tối. Kết quả cuối cùng sẽ có dạng như sau.
:root {
--surface-shadow-light: var(--brand-hue) 10% 20%;
--shadow-strength-light: .02;
}
.rad-shadow {
box-shadow:
0 2.8px 2.2px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .03)),
0 6.7px 5.3px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .01)),
0 12.5px 10px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .02)),
0 22.3px 17.9px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .02)),
0 41.8px 33.4px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .03)),
0 100px 80px hsl(var(--surface-shadow) / var(--shadow-strength))
;
}
Nếu muốn đi xa hơn với bóng trong bảng phối màu, tôi cũng sẽ đặt các góc bóng thành một mã thông báo thiết kế không đổi, vì hướng ánh sáng phải giống nhau giữa tất cả các bóng của thiết kế.
Sử dụng bảng phối màu
Khi đã xác định trước màu sắc, đã đến lúc biến các màu đó thành thuộc tính không phụ thuộc vào giao diện. Ý tôi là, với tư cách là tác giả CSS trong dự án bảng phối màu này, hiếm khi bạn cần truy cập vào giá trị của một bảng phối màu cụ thể. Tôi muốn giúp bạn dễ dàng tuân thủ chủ đề.
Để thực hiện việc này, bạn chỉ nên sử dụng bảng phối màu thông qua các thuộc tính tuỳ chỉnh chung mà chúng ta sẽ xác định trong giây lát. Bằng cách này, những người sử dụng biến thiết kế không bao giờ phải lo lắng về bảng phối màu hiện đang được đặt, họ chỉ cần sử dụng màu nền và màu văn bản. Thay vì color: var(--text1-light)
, hãy sử dụng color: var(--text1)
. Tất cả các hoạt động điều chỉnh và xoay màu đều được thực hiện ở cấp cao hơn nhiều trong CSS.
Hãy tìm hiểu sâu hơn về các kiểu kết nối của giao diện sáng trong khối mã sau đây,
kết nối một thuộc tính tuỳ chỉnh chung với màu cụ thể của giao diện sáng. Giờ đây, tất cả các trường hợp sử dụng var(--brand)
sẽ sử dụng màu thương hiệu sáng.
Giao diện sáng (tự động)
:root {
color-scheme: light;
--brand: var(--brand-light);
--text1: var(--text1-light);
--text2: var(--text2-light);
--surface1: var(--surface1-light);
--surface2: var(--surface2-light);
--surface3: var(--surface3-light);
--surface4: var(--surface4-light);
--surface-shadow: var(--surface-shadow-light);
--shadow-strength: var(--shadow-strength-light);
}
Trang web hiện đang sử dụng giao diện sáng. Đây là một khoảnh khắc thành công rất thú vị! Hãy cùng xem thêm một vài ví dụ khác về việc sử dụng màu được xác định trước trong các ngữ cảnh bảng phối màu khác.
Giao diện tối (tự động)
@media (prefers-color-scheme: dark) {
:root {
color-scheme: dark;
--brand: var(--brand-dark);
--text1: var(--text1-dark);
--text2: var(--text2-dark);
--surface1: var(--surface1-dark);
--surface2: var(--surface2-dark);
--surface3: var(--surface3-dark);
--surface4: var(--surface4-dark);
--surface-shadow: var(--surface-shadow-dark);
--shadow-strength: var(--shadow-strength-dark);
}
}
Giao diện sáng
[color-scheme="light"] {
color-scheme: light;
--brand: var(--brand-light);
--text1: var(--text1-light);
--text2: var(--text2-light);
--surface1: var(--surface1-light);
--surface2: var(--surface2-light);
--surface3: var(--surface3-light);
--surface4: var(--surface4-light);
--surface-shadow: var(--surface-shadow-light);
--shadow-strength: var(--shadow-strength-light);
}
Giao diện tối
[color-scheme="dark"] {
color-scheme: dark;
--brand: var(--brand-dark);
--text1: var(--text1-dark);
--text2: var(--text2-dark);
--surface1: var(--surface1-dark);
--surface2: var(--surface2-dark);
--surface3: var(--surface3-dark);
--surface4: var(--surface4-dark);
--surface-shadow: var(--surface-shadow-dark);
--shadow-strength: var(--shadow-strength-dark);
}
Giao diện tối
[color-scheme="dim"] {
color-scheme: dark;
--brand: var(--brand-dim);
--text1: var(--text1-dim);
--text2: var(--text2-dim);
--surface1: var(--surface1-dim);
--surface2: var(--surface2-dim);
--surface3: var(--surface3-dim);
--surface4: var(--surface4-dim);
--surface-shadow: var(--surface-shadow-dim);
--shadow-strength: var(--shadow-strength-dim);
}
Tại thời điểm này, tác giả có thể tự do sử dụng các giao diện màu chung được cung cấp nếu cần và không bao giờ phải lo lắng về giao diện nữa.
Kết luận
Giờ thì bạn đã biết cách tôi làm, còn bạn thì sao?! 🙂
Hãy đa dạng hoá các phương pháp và tìm hiểu tất cả các cách xây dựng trên web. Tạo một Codepen hoặc lưu trữ bản minh hoạ của riêng bạn, tweet cho tôi về bản minh hoạ đó và tôi sẽ thêm bản minh hoạ đó vào phần Bản phối lại của cộng đồng ở bên dưới.
Nguồn
Bản phối lại của cộng đồng – @chris-kruining đã thêm thanh trượt màu sắc, màu trạng thái và chế độ tương phản cho no-preference
, more
và less
: bản minh hoạ.