Nút bật/tắt chế độ tối cho phép người dùng ghi đè bảng phối màu của hệ thống cho một trang web.
Bạn có thể áp dụng chế độ ghi đè bằng cách cập nhật <meta name="color-scheme">: light dark có nghĩa là "tuân theo lựa chọn ưu tiên về hệ thống", light hoặc dark ghim một bảng phối màu rõ ràng.
Màu sắc (light-dark()), màu hệ thống và giao diện người dùng gốc đều dựa trên thuộc tính CSS color-scheme, vì vậy, nút bật/tắt hoạt động bằng cách giữ cho thuộc tính đó đồng bộ với <meta> (xem phần Phản ánh chế độ ghi đè trong CSS).
Nút bật/tắt cố định, chế độ kiểm soát cài đặt hay không có nút bật/tắt nào?
Hầu hết các trang web không cần nút bật/tắt bảng phối màu cố định trong giao diện người dùng của trang web (tiêu đề, thanh điều hướng, chân trang, v.v.). Theo mặc định, hãy tuân theo lựa chọn ưu tiên về hệ thống và nếu cần ghi đè thủ công, hãy đặt chế độ kiểm soát trong một giao diện cài đặt riêng: trang cài đặt, bảng điều khiển hoặc lớp phủ.
Việc ghim một bảng phối màu so với hệ điều hành là một ý định hợp lệ nhưng hiếm gặp, và những ý định hiếm gặp thuộc về việc tiết lộ dần dần, chứ không phải trong một chế độ điều khiển luôn hiển thị.
Nút bật/tắt cố định thường xuất hiện trên các trang web dành cho nhà phát triển hoặc liên quan đến nhà phát triển (ví dụ: dành cho nhà thiết kế), nơi việc chuyển đổi bảng phối màu là một thao tác thường xuyên hơn nhiều so với người dùng web thông thường. ĐỪNG thêm nút chỉ vì đó là một mẫu phổ biến trên các trang web dành cho nhà phát triển: mối quan tâm của nhà phát triển đối với chế độ kiểm soát này không đại diện cho người dùng thông thường.
Triển khai
Trước tiên, hãy làm theo tất cả các bước trong Chế độ tối để hỗ trợ cả hai bảng phối màu, mặc định là lựa chọn ưu tiên về hệ thống.
Mô hình dữ liệu
Mô hình dữ liệu cho nút bật/tắt chế độ tối thường bao gồm ba trạng thái:
- Hệ thống (không có giá trị được lưu trữ): Giao diện người dùng tuân theo bảng phối màu của hệ thống. Tốt nhất là bạn nên đặt chế độ này làm mặc định.
- Sáng (được lưu trữ dưới dạng
"light"): Giao diện người dùng sử dụng giao diện sáng bất kể bảng phối màu của hệ thống. - Tối (được lưu trữ dưới dạng
"dark"): Giao diện người dùng sử dụng giao diện tối bất kể bảng phối màu của hệ thống.
Trạng thái này thường được lưu trữ trong localStorage và được phản ánh trong phần tử <meta name="color-scheme"> ở đầu tài liệu.
Phản ánh cơ chế ghi đè trong CSS
<meta> chỉ là một gợi ý trình bày: mọi nội dung khai báo color-scheme trong CSS của tác giả đều ghi đè gợi ý này.
Vì Chế độ tối đặt color-scheme: light dark trên :root, nên việc chỉ cập nhật <meta> là không hoạt động — CSS sẽ thắng.
Ánh xạ <meta> trở lại thuộc tính để hiệu ứng xếp tầng tuân theo thuộc tính đó:
:root {
color-scheme: light dark;
&:has(> head > meta[name="color-scheme"][content="dark"]) {
color-scheme: dark;
}
&:has(> head > meta[name="color-scheme"][content="light"]) {
color-scheme: light;
}
}
KHÔNG cố định giá trị color-scheme: light hoặc color-scheme: dark trong mã làm giá trị mặc định gốc; nội dung khai báo cơ sở PHẢI là light dark.
CSS KHÔNG ĐƯỢC phụ thuộc vào JS: nếu JS không bao giờ chạy, <meta> sẽ giữ nguyên light dark và trang web sẽ tuân theo lựa chọn ưu tiên về hệ thống — không có gì bị hỏng.
Tính bền vững và ngăn chặn FOUC
Lưu giữ chế độ ghi đè trong localStorage; xoá mục nhập khi quay lại theo giá trị mặc định của hệ thống.
Để tránh hiện nhầm giao diện, hãy áp dụng giá trị được lưu trữ trong tập lệnh cùng dòng (KHÔNG PHẢI type=module, KHÔNG PHẢI defer) được đặt ngay sau phần tử <meta>:
<meta name="color-scheme" content="light dark">
<script>
document.querySelector('meta[name="color-scheme"]').content = localStorage.getItem("color-scheme") ?? "light dark";
</script>
- Tập lệnh cùng dòng này chỉ dùng để ngăn chặn FOUC. Hãy giữ cho tệp này nhỏ nhất có thể; JS bổ sung để xử lý việc chuyển đổi bảng phối màu có thể tải sau.
- Trong một số ít trường hợp, quyền truy cập
localStoragecó thể gửi (ví dụ: dữ liệu trang web bị chặn), nhưng vì tập lệnh này không làm gì khác, nên tác dụng phụ duy nhất sẽ là lỗi bảng điều khiển. Gói trongtry .. catchnếu điều này quan trọng. Đảm bảo giao diện vẫn được áp dụng cho trang, ngay cả khi không thể duy trì giao diện. - Giá trị ghi đè có thể thay đổi từ một thẻ khác: xử lý sự kiện
storagecủawindowđể luôn đồng bộ hoá. - KHÔNG sử dụng
matchMedia()để xoá giá trị được lưu trữ khi lựa chọn ưu tiên về hệ thống thay đổi cho phù hợp với giá trị đó. Hệ điều hành của nhiều người dùng tự động chuyển đổi bảng phối màu dựa trên thời gian trong ngày; việc xoá giá trị được lưu trữ bất cứ khi nào hai bảng phối màu trùng nhau sẽ khiến bạn không thể ghim bảng phối màu.
Phân nhánh cho HTML và các giá trị không phải màu
Màu sắc không cần thêm thao tác nào: sau khi <meta> được liên kết với color-scheme (ở trên), light-dark() sẽ tuân theo cơ chế ghi đè.
Phần này nói về việc điều chỉnh các giá trị khác (ví dụ: font-weight, nguồn nội dung nghe nhìn, v.v.).
Khi trang chỉ tuân theo lựa chọn ưu tiên về hệ thống, bạn có thể dùng (prefers-color-scheme: dark) để phân nhánh, kể cả trong các nguồn <picture> hoặc <video>.
Việc ghi đè bảng phối màu sẽ gây thêm một vấn đề phức tạp: lựa chọn ưu tiên về hệ thống không còn là nguồn đáng tin cậy và đối với các API chỉ chấp nhận truy vấn đa phương tiện, không có giải pháp thay thế trực tiếp.
KHÔNG chỉ dựa vào các lớp do JS áp dụng như .dark để phân nhánh, vì các lớp này sẽ không chính xác nếu JS không tải và chế độ mặc định của hệ điều hành là tối.
Bạn có thể kết hợp truy vấn đa phương tiện với bộ chọn :root:has(> head > meta[name="color-scheme"][content="dark"]) (hoặc light) để phân nhánh.
Hãy xem phần Bộ chọn và tổ hợp quy tắc @ để biết thông tin chi tiết về cách triển khai một cách hiệu quả.
Các tuỳ chọn của thành phần điều khiển cũng là các nhánh không có màu: bao gồm cả hai trạng thái trong mã đánh dấu (biểu tượng cộng với văn bản hành động bị ẩn, ví dụ: "Chuyển sang giao diện tối") và ẩn trạng thái không hoạt động thông qua các bộ chọn này.
display: none cũng xoá lựa chọn thừa khỏi AT để chế độ kiểm soát không cần JS để luôn cập nhật khi lựa chọn ưu tiên về hệ thống thay đổi.
Đối với nội dung nghe nhìn trong HTML, cách duy nhất hiện tại là thêm cả hai phiên bản dưới dạng các phần tử riêng biệt và bật/tắt chế độ hiển thị một cách thích hợp.
Việc ẩn các phần tử <source> bằng display: none không hoạt động.
Giao diện người dùng
Hai hay ba trạng thái?
Trong mọi trường hợp, giao diện người dùng PHẢI hỗ trợ việc chuyển về hoặc đặt bảng phối màu theo hệ thống.
Ưu tiên hiển thị hai trạng thái trong các nút bật/tắt có không gian hạn chế, chẳng hạn như các nút bật/tắt cố định trong giao diện trang web (tiêu đề, thanh điều hướng, chân trang, v.v.) nơi không gian bị hạn chế và việc điều chỉnh chế độ cài đặt thường không liên quan đến mục tiêu của người dùng.
Chế độ kiểm soát bảng phối màu trong một giao diện cài đặt riêng biệt (trang, bảng điều khiển hoặc lớp phủ) là một trường hợp khác và CÓ THỂ hiển thị rõ ràng cả ba trạng thái ("Sáng", "Tối", "Hệ thống"): tại đó, người dùng đã đưa ra quyết định có chủ ý về hành vi trong tương lai và có không gian để giải thích các lựa chọn.
Ba trạng thái rõ ràng cũng được đảm bảo nếu trang web triển khai các lược đồ nhận biết theo bối cảnh (ví dụ: chế độ sáng mờ hơn khi hệ điều hành ở chế độ tối), vì khi đó "Sáng" và "Hệ thống (hiện đang sáng)" thực sự khác nhau.
Nút bật/tắt hai trạng thái
Khi sử dụng một chế độ điều khiển như vậy, người dùng thường có xu hướng điều chỉnh tạm thời cho dễ chịu ("hiện tại quá sáng") thay vì đảm bảo trạng thái hiện tại được duy trì lâu dài. Do đó, đối với nút bật/tắt hai trạng thái, bạn chỉ cần hiển thị hai trong số ba chế độ cài đặt: hệ thống (để có thể huỷ bỏ chế độ cài đặt) và chế độ cài đặt hiện tại ngược với hệ thống, được lưu trữ dưới dạng giá trị cố định hiện tại.
Hai trạng thái duy nhất phải là:
- Theo giá trị mặc định của hệ thống — không có giá trị được lưu trữ, nội dung
<meta>light dark. Hiển thị dưới dạng giá trị đã phân giải hiện tại (ví dụ: biểu tượng mặt trời khi sáng). - Ghi đè — được lưu trữ theo đúng nghĩa đen là
lighthoặcdark.
Về cơ bản, đây là chế độ kiểm soát ba trạng thái (light dark, light, dark), trong đó không thể truy cập vào trạng thái rõ ràng khớp với lựa chọn ưu tiên về hệ thống hiện tại.
Khi người dùng bật/tắt:
- Bảng phối màu mục tiêu = ngược lại với bảng phối màu hiện đang hiển thị (giá trị được lưu trữ nếu có, nếu không thì là lựa chọn ưu tiên về hệ thống). Ý định của người dùng là "chọn chế độ ngược lại với chế độ tôi đang thấy", chứ KHÔNG phải "chọn chế độ ngược lại với chế độ mặc định của hệ thống".
- Nếu mục tiêu khác với lựa chọn ưu tiên về hệ thống hiện tại, hãy lưu trữ mục tiêu đó theo đúng nghĩa đen.
- Nếu mục tiêu khớp với lựa chọn ưu tiên hiện tại của hệ thống, thì người dùng đang huỷ bỏ điều chỉnh của họ: xoá giá trị được lưu trữ. KHÔNG lưu trữ bảng phối màu này — việc này sẽ ghim bảng phối màu một cách vô hình trước những thay đổi trong tương lai của hệ thống.
- Đặt nội dung
<meta>thành giá trị được lưu trữ hoặclight darknếu không có.
QUAN TRỌNG: Chỉ được kiểm tra sự khác biệt tại thời điểm lưu trữ, không được kiểm tra hồi tố: giá trị được lưu trữ mà sau đó lựa chọn ưu tiên về hệ thống thay đổi cho phù hợp PHẢI được giữ lại. Hệ điều hành của nhiều người dùng tự động chuyển đổi bảng phối màu dựa trên thời gian trong ngày; việc xoá giá trị được lưu trữ bất cứ khi nào hai bảng phối màu trùng nhau sẽ khiến bạn không thể ghim bảng phối màu.
Tình huống ví dụ, bắt đầu bằng việc đặt hệ điều hành ở chế độ sáng:
- Người dùng bật/tắt. Chế độ tối khác với lựa chọn ưu tiên về hệ thống, vì vậy,
darksẽ được lưu trữ; trang web chuyển sang chế độ tối. - Chế độ cài đặt hệ điều hành thay đổi thành tối. Trang web vẫn ở chế độ tối (giá trị được lưu trữ hiện khớp với lựa chọn ưu tiên về hệ thống, nhưng vẫn được giữ lại).
- Chế độ cài đặt hệ điều hành thay đổi trở lại thành giao diện sáng. Trang web vẫn ở chế độ tối.
- Người dùng bật/tắt. Chế độ mục tiêu (sáng) khớp với lựa chọn ưu tiên về hệ thống, vì vậy, giá trị được lưu trữ sẽ bị xoá và trang web sẽ lại tuân theo hệ thống.
Nút bật/tắt ba trạng thái
Khi có nhiều không gian hơn và người dùng đã có ý định đặt lựa chọn ưu tiên dài hạn, thì chế độ kiểm soát ba trạng thái có thể giúp người dùng hiểu rõ hơn. Trong trường hợp này, mô hình dữ liệu liên kết rõ ràng với 3 lựa chọn giao diện người dùng: hệ thống, sáng và tối.
Để giảm tải nhận thức, tuỳ chọn "hệ thống" cũng sẽ hiển thị chế độ cài đặt hiện tại của hệ thống, ví dụ: thông qua:
- Biểu tượng, ví dụ: biểu tượng mặt trời ở dưới cùng bên phải của biểu tượng hệ thống
- Văn bản, ví dụ: "Hệ thống (Hiện đang sáng)"