Preferreds-color-scheme: Xin chào bóng tối, bạn cũ của tôi

Được thổi phồng quá mức hay là một nhu cầu thiết yếu? Tìm hiểu mọi thứ về chế độ tối và cách hỗ trợ chế độ này để mang lại lợi ích cho người dùng!

Giới thiệu

Chế độ tối trước khi có Chế độ tối

Một chiếc máy tính cũ (trước những năm 90) có văn bản màu xanh lục trên nền đen.
Phông xanh (Nguồn)

Chúng tôi đã hoàn tất việc triển khai chế độ tối. Vào buổi bình minh của điện toán cá nhân, chế độ tối không phải là vấn đề lựa chọn mà là một thực tế: Màn hình máy tính CRT đơn sắc hoạt động bằng cách bắn các chùm tia điện tử lên màn hình lân quang và chất lân quang được sử dụng trong CRT ban đầu có màu xanh lục. Vì văn bản hiển thị bằng màu xanh lục và phần còn lại của màn hình có màu đen, nên những mẫu này thường được gọi là màn hình xanh lục.

Màn hình hiển thị phiên bản Windows 3.1 của Microsoft Word.
Chữ tối trên nền trắng (Nguồn)

Các CRT màu được giới thiệu sau đó hiển thị nhiều màu thông qua việc sử dụng các chất lân quang màu đỏ, xanh lục và xanh dương. Họ tạo ra màu trắng bằng cách kích hoạt đồng thời cả 3 chất lân quang. Với sự ra đời của WYSIWYG (nhìn thấy gì là nhận được nấy) tinh vi hơn trong xuất bản trên máy tính, ý tưởng tạo ra tài liệu ảo giống như một tờ giấy thực tế đã trở nên phổ biến.

Một cụm cửa sổ hiển thị các trang web có chữ màu tối trên nền trắng trong trình duyệt WorldWideWeb đời đầu.
Trình duyệt WorldWideWeb (Nguồn)

Đây là nơi bắt đầu xu hướng thiết kế chữ tối trên nền trắng và xu hướng này được chuyển sang web dựa trên tài liệu ban đầu. Trình duyệt đầu tiên trên thế giới, WorldWideWeb (hãy nhớ rằng CSS thậm chí còn chưa được phát minh) hiển thị các trang web theo cách này. Sự thật thú vị: trình duyệt thứ hai từng xuất hiện, Line Mode Browser (một trình duyệt dựa trên thiết bị đầu cuối) có màu xanh lục trên nền tối. Ngày nay, các trang web và ứng dụng web thường được thiết kế với văn bản tối trên nền sáng, một giả định cơ bản cũng được mã hoá cứng trong biểu định kiểu tác nhân người dùng, bao gồm cả Chrome.

Điện thoại di động được dùng trên giường

Thời của CRT đã qua từ lâu. Việc tiêu thụ và sáng tạo nội dung đã chuyển sang các thiết bị di động sử dụng màn hình LCD có đèn nền hoặc màn hình AMOLED tiết kiệm năng lượng. Máy tính, máy tính bảng và điện thoại thông minh nhỏ gọn và dễ mang theo hơn đã dẫn đến các mẫu hình sử dụng mới. Các hoạt động giải trí như duyệt web, viết mã cho vui và chơi game cao cấp thường diễn ra ngoài giờ làm việc trong môi trường ánh sáng yếu. Mọi người thậm chí còn dùng thiết bị trên giường vào ban đêm. Càng nhiều người sử dụng thiết bị trong bóng tối, ý tưởng quay trở lại nguồn gốc của chế độ sáng trên nền tối càng trở nên phổ biến.

Lý do nên dùng chế độ tối

Chế độ tối vì lý do thẩm mỹ

Khi được hỏi vì sao họ thích hoặc muốn dùng chế độ tối, câu trả lời phổ biến nhất là "chế độ này giúp mắt dễ chịu hơn", tiếp theo là "chế độ này trông trang nhã và đẹp mắt". Apple trong tài liệu dành cho nhà phát triển về Chế độ tối đã viết rõ ràng rằng: "Việc chọn bật giao diện sáng hay tối là một lựa chọn thẩm mỹ đối với hầu hết người dùng và có thể không liên quan đến điều kiện ánh sáng xung quanh."

CloseView trong Hệ thống 7 của Mac OS ở chế độ "Chữ trắng trên nền đen" (Nguồn)

Chế độ tối là một công cụ hỗ trợ tiếp cận

Ngoài ra, có những người thực sự cần chế độ tối và sử dụng chế độ này như một công cụ hỗ trợ tiếp cận khác, chẳng hạn như người dùng có thị lực kém. Công cụ hỗ trợ tiếp cận sớm nhất mà tôi có thể tìm thấy là tính năng CloseView của System 7. Tính năng này có nút bật/tắt cho chế độ Chữ đen trên nền trắngChữ trắng trên nền đen. Mặc dù System 7 có hỗ trợ màu sắc, nhưng giao diện người dùng mặc định vẫn là đen trắng.

Những cách triển khai dựa trên việc đảo ngược này đã cho thấy điểm yếu khi màu sắc được đưa vào. Nghiên cứu người dùng của Szpiro và cộng sự về cách người có thị lực kém truy cập vào các thiết bị điện toán cho thấy tất cả người dùng được phỏng vấn đều không thích hình ảnh đảo ngược, nhưng nhiều người thích văn bản sáng trên nền tối. Apple đáp ứng lựa chọn ưu tiên này của người dùng bằng một tính năng có tên là Đảo ngược thông minh. Tính năng này đảo ngược màu sắc trên màn hình, ngoại trừ hình ảnh, nội dung nghe nhìn và một số ứng dụng sử dụng kiểu màu tối.

Một dạng đặc biệt của thị lực kém là Hội chứng thị lực do máy tính, còn được gọi là Mỏi mắt do thiết bị điện tử. Hội chứng này được định nghĩa"tình trạng kết hợp giữa các vấn đề về mắt và thị lực liên quan đến việc sử dụng máy tính (bao gồm cả máy tính để bàn, máy tính xách tay và máy tính bảng) và các màn hình điện tử khác (ví dụ: điện thoại thông minh và thiết bị đọc sách điện tử)." Người ta đề xuất rằng việc thanh thiếu niên sử dụng thiết bị điện tử, đặc biệt là vào ban đêm, sẽ làm tăng nguy cơ giảm thời lượng ngủ, thời gian đi vào giấc ngủ lâu hơn và tăng tình trạng thiếu ngủ. Ngoài ra, việc tiếp xúc với ánh sáng xanh đã được báo cáo rộng rãi là có liên quan đến việc điều chỉnh nhịp sinh học và chu kỳ ngủ. Theo nghiên cứu của Rosenfield, môi trường ánh sáng không đều có thể dẫn đến tình trạng thiếu ngủ, có thể ảnh hưởng đến tâm trạng và hiệu suất công việc. Để hạn chế những tác động tiêu cực này, bạn có thể giảm ánh sáng xanh bằng cách điều chỉnh nhiệt độ màu của màn hình thông qua các tính năng như Night Shift của iOS hoặc Ánh sáng đêm của Android, cũng như tránh ánh sáng mạnh hoặc ánh sáng không đều nói chung thông qua các Giao diện tối hoặc chế độ tối.

Tiết kiệm pin khi dùng chế độ tối trên màn hình AMOLED

Cuối cùng, chế độ tối được biết đến là giúp tiết kiệm rất nhiều năng lượng trên màn hình AMOLED. Các nghiên cứu điển hình về Android tập trung vào các ứng dụng phổ biến của Google như YouTube cho thấy mức tiết kiệm pin có thể lên đến 60%. Video dưới đây có thêm thông tin chi tiết về những nghiên cứu điển hình này và mức tiết kiệm điện cho mỗi ứng dụng.

Kích hoạt chế độ tối trong hệ điều hành

Giờ đây, khi đã trình bày bối cảnh về lý do khiến chế độ tối trở nên quan trọng đối với nhiều người dùng, hãy cùng xem xét cách bạn có thể hỗ trợ chế độ này.

Chế độ cài đặt chế độ tối trên Android Q

Các hệ điều hành hỗ trợ chế độ tối hoặc giao diện tối thường có một lựa chọn để kích hoạt chế độ này ở đâu đó trong phần cài đặt. Trên macOS X, chế độ này nằm trong phần Chung của phần cài đặt hệ thống và có tên là Giao diện (ảnh chụp màn hình), còn trên Windows 10, chế độ này nằm trong phần Màu sắc và có tên là Chọn màu (ảnh chụp màn hình). Đối với Android Q, bạn có thể tìm thấy chế độ này trong phần Màn hình dưới dạng nút bật/tắt Giao diện tối (ảnh chụp màn hình), còn trên iOS 13, bạn có thể thay đổi Giao diện trong phần Màn hình và độ sáng của phần cài đặt (ảnh chụp màn hình).

Truy vấn nội dung nghe nhìn prefers-color-scheme

Một chút lý thuyết cuối cùng trước khi tôi bắt đầu. Truy vấn nội dung nghe nhìn cho phép tác giả kiểm thử và truy vấn các giá trị hoặc tính năng của tác nhân người dùng hoặc thiết bị hiển thị, độc lập với tài liệu đang được hiển thị. Chúng được dùng trong quy tắc CSS @media để áp dụng có điều kiện các kiểu cho một tài liệu, cũng như trong nhiều ngữ cảnh và ngôn ngữ khác, chẳng hạn như HTML và JavaScript. Media Queries Level 5 (Truy vấn nội dung nghe nhìn cấp 5) giới thiệu các tính năng nội dung nghe nhìn theo lựa chọn ưu tiên của người dùng. Đây là cách để các trang web phát hiện cách người dùng muốn hiển thị nội dung.

Tính năng prefers-color-scheme nội dung nghe nhìn được dùng để phát hiện xem người dùng có yêu cầu trang sử dụng giao diện màu sáng hay tối hay không. Tham số này hoạt động với các giá trị sau:

  • light: Cho biết người dùng đã thông báo cho hệ thống rằng họ muốn một trang có giao diện sáng (văn bản tối trên nền sáng).
  • dark: Cho biết người dùng đã thông báo cho hệ thống rằng họ muốn một trang có giao diện tối (văn bản sáng trên nền tối).

Hỗ trợ chế độ tối

Tìm hiểu xem trình duyệt có hỗ trợ chế độ tối hay không

Vì chế độ tối được báo cáo thông qua một truy vấn nội dung nghe nhìn, nên bạn có thể dễ dàng kiểm tra xem trình duyệt hiện tại có hỗ trợ chế độ tối hay không bằng cách kiểm tra xem truy vấn nội dung nghe nhìn prefers-color-scheme có khớp hay không. Lưu ý rằng tôi không thêm bất kỳ giá trị nào, mà chỉ kiểm tra xem truy vấn nội dung nghe nhìn có khớp hay không.

if (window.matchMedia('(prefers-color-scheme)').media !== 'not all') {
  console.log('🎉 Dark mode is supported');
}

Tại thời điểm viết bài này, prefers-color-scheme được Chrome và Edge hỗ trợ trên cả máy tính và thiết bị di động (nếu có) từ phiên bản 76, Firefox từ phiên bản 67 và Safari từ phiên bản 12.1 trên macOS và từ phiên bản 13 trên iOS. Đối với tất cả các trình duyệt khác, bạn có thể xem tài liệu Can I use support tables (Tôi có thể sử dụng bảng hỗ trợ không).

Tìm hiểu về các lựa chọn ưu tiên của người dùng tại thời điểm yêu cầu

Tiêu đề gợi ý cho ứng dụng Sec-CH-Prefers-Color-Scheme cho phép các trang web tuỳ ý lấy thông tin về lựa chọn ưu tiên của người dùng đối với bảng phối màu tại thời điểm yêu cầu, cho phép các máy chủ nội tuyến CSS phù hợp và do đó tránh được tình trạng nhấp nháy chủ đề màu không chính xác.

Chế độ tối trong thực tế

Cuối cùng, hãy xem cách hỗ trợ chế độ tối trong thực tế. Giống như trong bộ phim Highlander, với chế độ tối chỉ có thể có một: tối hoặc sáng, nhưng không bao giờ có cả hai! Tại sao tôi lại đề cập đến vấn đề này? Vì thực tế này sẽ ảnh hưởng đến chiến lược tải. Vui lòng không buộc người dùng tải CSS xuống trong đường dẫn hiển thị quan trọng cho một chế độ mà họ hiện không sử dụng. Để tối ưu hoá tốc độ tải, tôi đã chia CSS cho ứng dụng ví dụ cho thấy các đề xuất sau trên thực tế thành 3 phần để hoãn CSS không quan trọng:

  • style.css chứa các quy tắc chung được sử dụng trên toàn bộ trang web.
  • dark.css chỉ chứa các quy tắc cần thiết cho chế độ tối.
  • light.css chỉ chứa các quy tắc cần thiết cho chế độ sáng.

Chiến lược tải

Hai thao tác sau, light.cssdark.css, được tải có điều kiện bằng truy vấn <link media>. Ban đầu, không phải trình duyệt nào cũng hỗ trợ prefers-color-scheme (có thể phát hiện bằng mẫu ở trên), mà tôi xử lý động bằng cách tải tệp light.css mặc định thông qua một phần tử <link rel="stylesheet"> được chèn có điều kiện trong một tập lệnh nội tuyến rất nhỏ (light là một lựa chọn tuỳ ý, tôi cũng có thể chọn dark làm trải nghiệm dự phòng mặc định). Để tránh nội dung chưa được tạo kiểu xuất hiện chớp nhoáng, tôi ẩn nội dung của trang cho đến khi light.css tải xong.

<script>
  // If `prefers-color-scheme` is not supported, fall back to light mode.
  // In this case, light.css will be downloaded with `highest` priority.
  if (window.matchMedia('(prefers-color-scheme: dark)').media === 'not all') {
    document.documentElement.style.display = 'none';
    document.head.insertAdjacentHTML(
      'beforeend',
      '<link rel="stylesheet" href="/light.css" onload="document.documentElement.style.display = \'\'">',
    );
  }
</script>
<!--
  Conditionally either load the light or the dark stylesheet. The matching file
  will be downloaded with `highest`, the non-matching file with `lowest`
  priority. If the browser doesn't support `prefers-color-scheme`, the media
  query is unknown and the files are downloaded with `lowest` priority (but
  above I already force `highest` priority for my default light experience).
-->
<link rel="stylesheet" href="/dark.css" media="(prefers-color-scheme: dark)" />
<link
  rel="stylesheet"
  href="/light.css"
  media="(prefers-color-scheme: light)"
/>
<!-- The main stylesheet -->
<link rel="stylesheet" href="/style.css" />

Cấu trúc biểu định kiểu

Tôi tận dụng tối đa các biến CSS, điều này cho phép style.css chung của tôi trở nên chung chung và mọi hoạt động tuỳ chỉnh chế độ sáng hoặc tối đều diễn ra trong hai tệp khác dark.csslight.css. Dưới đây là một đoạn trích về các kiểu chữ thực tế, nhưng đoạn trích này đủ để truyền tải ý tưởng tổng thể. Tôi khai báo hai biến, -⁠-⁠color-⁠-⁠background-color. Về cơ bản, hai biến này sẽ tạo ra một giao diện cơ bản tối trên nền sáng và một giao diện cơ bản sáng trên nền tối.

/* light.css: 👉 dark-on-light */
:root {
  --color: rgb(5, 5, 5);
  --background-color: rgb(250, 250, 250);
}
/* dark.css: 👉 light-on-dark */
:root {
  --color: rgb(250, 250, 250);
  --background-color: rgb(5, 5, 5);
}

Trong style.css, sau đó tôi sử dụng những biến này trong quy tắc body { … }. Vì được xác định trên :root lớp giả CSS – một bộ chọn đại diện cho phần tử <html> trong HTML và giống với bộ chọn html, ngoại trừ độ cụ thể cao hơn – nên chúng xếp tầng xuống, điều này giúp tôi khai báo các biến CSS chung.

/* style.css */
:root {
  color-scheme: light dark;
}

body {
  color: var(--color);
  background-color: var(--background-color);
}

Trong đoạn mã mẫu ở trên, có lẽ bạn đã nhận thấy một thuộc tính color-scheme có giá trị light dark được phân tách bằng dấu cách.

Điều này cho trình duyệt biết những giao diện màu mà ứng dụng của tôi hỗ trợ và cho phép trình duyệt kích hoạt các biến thể đặc biệt của biểu định kiểu tác nhân người dùng. Điều này hữu ích khi, chẳng hạn như, cho phép trình duyệt kết xuất các trường biểu mẫu có nền tối và văn bản sáng, điều chỉnh thanh cuộn hoặc bật màu làm nổi bật theo giao diện. Thông tin chi tiết chính xác về color-scheme được chỉ định trong CSS Color Adjustment Module Level 1 (Mô-đun điều chỉnh màu CSS cấp 1).

Sau đó, mọi thứ khác chỉ là vấn đề xác định các biến CSS cho những thứ quan trọng trên trang web của tôi. Việc sắp xếp các kiểu theo ngữ nghĩa sẽ rất hữu ích khi bạn làm việc với chế độ tối. Ví dụ: thay vì -⁠-⁠highlight-yellow, hãy cân nhắc gọi biến -⁠-⁠accent-color, vì "vàng" thực sự có thể không phải là màu vàng ở chế độ tối hoặc ngược lại. Dưới đây là ví dụ về một số biến khác mà tôi sử dụng trong ví dụ của mình.

/* dark.css */
:root {
  --color: rgb(250, 250, 250);
  --background-color: rgb(5, 5, 5);
  --link-color: rgb(0, 188, 212);
  --main-headline-color: rgb(233, 30, 99);
  --accent-background-color: rgb(0, 188, 212);
  --accent-color: rgb(5, 5, 5);
}
/* light.css */
:root {
  --color: rgb(5, 5, 5);
  --background-color: rgb(250, 250, 250);
  --link-color: rgb(0, 0, 238);
  --main-headline-color: rgb(0, 0, 192);
  --accent-background-color: rgb(0, 0, 238);
  --accent-color: rgb(250, 250, 250);
}

Ví dụ đầy đủ

Trong phần nhúng Glitch sau đây, bạn có thể xem ví dụ hoàn chỉnh về cách áp dụng các khái niệm ở trên vào thực tế. Hãy thử bật/tắt chế độ tối trong phần cài đặt của hệ điều hành cụ thể mà bạn đang dùng và xem trang phản ứng như thế nào.

Tác động của việc tải

Khi thử nghiệm với ví dụ này, bạn có thể thấy lý do tôi tải dark.csslight.css thông qua các truy vấn nội dung nghe nhìn. Hãy thử bật/tắt chế độ tối rồi tải lại trang: các biểu định kiểu cụ thể hiện không khớp vẫn được tải, nhưng có mức độ ưu tiên thấp nhất, để chúng không bao giờ cạnh tranh với những tài nguyên mà trang web cần ngay bây giờ.

Sơ đồ tải mạng cho thấy cách CSS của chế độ tối được tải với mức độ ưu tiên thấp nhất trong chế độ sáng.
Trang web ở chế độ sáng tải CSS chế độ tối với mức độ ưu tiên thấp nhất.
Sơ đồ tải mạng cho thấy cách CSS ở chế độ sáng được tải với mức độ ưu tiên thấp nhất trong chế độ tối.
Trang web ở chế độ tối tải CSS ở chế độ sáng với mức độ ưu tiên thấp nhất.
Sơ đồ tải mạng cho thấy cách CSS của chế độ tối được tải với mức độ ưu tiên thấp nhất trong chế độ sáng mặc định.
Trang web ở chế độ sáng mặc định trên trình duyệt không hỗ trợ prefers-color-scheme sẽ tải CSS ở chế độ tối với mức độ ưu tiên thấp nhất.

Phản hồi các thay đổi về chế độ tối

Giống như mọi thay đổi khác về truy vấn nội dung nghe nhìn, bạn có thể đăng ký nhận các thay đổi về chế độ tối thông qua JavaScript. Ví dụ: bạn có thể dùng thuộc tính này để thay đổi linh động favicon của một trang hoặc thay đổi <meta name="theme-color"> xác định màu của thanh URL trong Chrome. Ví dụ đầy đủ ở trên cho thấy điều này đang diễn ra. Để xem các thay đổi về màu sắc giao diện và biểu tượng trang web, hãy mở bản minh hoạ trong một thẻ riêng.

const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
darkModeMediaQuery.addEventListener('change', (e) => {
  const darkModeOn = e.matches;
  console.log(`Dark mode is ${darkModeOn ? '🌒 on' : '☀️ off'}.`);
});

Kể từ Chromium 93 và Safari 15, bạn có thể điều chỉnh màu dựa trên một truy vấn nội dung nghe nhìn bằng thuộc tính media của phần tử màu giao diện meta. Hệ thống sẽ chọn mục đầu tiên khớp với tiêu chí. Ví dụ: bạn có thể có một màu cho chế độ sáng và một màu khác cho chế độ tối. Tại thời điểm viết bài này, bạn không thể xác định những thành phần đó trong tệp kê khai. Xem vấn đề w3c/manifest#975 trên GitHub.

<meta
  name="theme-color"
  media="(prefers-color-scheme: light)"
  content="white"
/>
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="black" />

Gỡ lỗi và kiểm thử chế độ tối

Mô phỏng prefers-color-scheme trong Công cụ cho nhà phát triển

Việc chuyển đổi toàn bộ bảng phối màu của hệ điều hành có thể gây khó chịu rất nhanh, vì vậy, Chrome DevTools hiện cho phép bạn mô phỏng bảng phối màu mà người dùng ưu tiên theo cách chỉ ảnh hưởng đến thẻ hiện đang hiển thị. Mở Trình đơn lệnh, bắt đầu nhập Rendering, chạy lệnh Show Rendering, rồi thay đổi lựa chọn Mô phỏng tính năng đa phương tiện prefers-color-scheme của CSS.

Ảnh chụp màn hình của lựa chọn &quot;Mô phỏng tính năng đa phương tiện prefers-color-scheme của CSS&quot; nằm trong thẻ Kết xuất của Chrome DevTools.

Chụp ảnh màn hình prefers-color-scheme bằng Puppeteer

Puppeteer là một thư viện Node.js cung cấp API cấp cao để kiểm soát Chrome hoặc Chromium thông qua Giao thức DevTools. Với dark-mode-screenshot, chúng tôi cung cấp một tập lệnh Puppeteer cho phép bạn tạo ảnh chụp màn hình các trang ở cả chế độ tối và chế độ sáng. Bạn có thể chạy tập lệnh này một lần hoặc đưa tập lệnh này vào bộ kiểm thử Tích hợp liên tục (CI).

npx dark-mode-screenshot --url https://googlechromelabs.github.io/dark-mode-toggle/demo/ --output screenshot --fullPage --pause 750

Các phương pháp hay nhất về chế độ tối

Tránh màu trắng tinh khiết

Một chi tiết nhỏ mà bạn có thể nhận thấy là tôi không sử dụng màu trắng tinh khiết. Thay vào đó, để ngăn hiện tượng phát sáng và tràn màu lên nội dung tối xung quanh, tôi chọn màu trắng hơi tối hơn. Một số nội dung như rgb(250, 250, 250) hoạt động hiệu quả.

Tô màu lại và làm tối hình ảnh chụp

Nếu so sánh hai ảnh chụp màn hình bên dưới, bạn sẽ nhận thấy rằng không chỉ chủ đề cốt lõi thay đổi từ chữ tối trên nền sáng thành chữ sáng trên nền tối, mà hình ảnh chính cũng có vẻ hơi khác. Nghiên cứu người dùng của tôi cho thấy đa số người được khảo sát thích những hình ảnh ít sống động và rực rỡ hơn một chút khi chế độ tối đang hoạt động. Tôi gọi đây là tái tạo màu.

Hình ảnh chính hơi tối đi ở chế độ tối.
Hình ảnh chính thông thường ở chế độ sáng.

Tôi có thể đổi màu bằng bộ lọc CSS trên hình ảnh của mình. Tôi sử dụng bộ chọn CSS khớp với tất cả hình ảnh không có .svg trong URL của chúng, ý tưởng là tôi có thể xử lý việc đổi màu cho đồ hoạ vectơ (biểu tượng) khác với hình ảnh (ảnh) của mình, tìm hiểu thêm về điều này trong đoạn văn tiếp theo. Lưu ý cách tôi sử dụng lại biến CSS, để sau này tôi có thể linh hoạt thay đổi bộ lọc của mình.

Vì chỉ cần đổi màu ở chế độ tối, tức là khi dark.css đang hoạt động, nên không có quy tắc tương ứng nào trong light.css.

/* dark.css */
--image-filter: grayscale(50%);

img:not([src*='.svg']) {
  filter: var(--image-filter);
}

Tuỳ chỉnh cường độ đổi màu của chế độ tối bằng JavaScript

Không phải ai cũng giống nhau và mỗi người có nhu cầu khác nhau về chế độ tối. Bằng cách tuân thủ phương pháp đổi màu như mô tả ở trên, tôi có thể dễ dàng biến cường độ thang độ xám thành lựa chọn ưu tiên của người dùng mà tôi có thể thay đổi thông qua JavaScript. Ngoài ra, bằng cách đặt giá trị 0%, tôi cũng có thể tắt hoàn toàn tính năng đổi màu. Xin lưu ý rằng document.documentElement cung cấp một thông tin tham chiếu đến phần tử gốc của tài liệu, tức là phần tử tương tự mà tôi có thể tham chiếu bằng lớp giả CSS :root.

const filter = 'grayscale(70%)';
document.documentElement.style.setProperty('--image-filter', value);

Đảo ngược đồ hoạ vectơ và biểu tượng

Đối với đồ hoạ vectơ (trong trường hợp của tôi, đồ hoạ này được dùng làm biểu tượng mà tôi tham chiếu thông qua các phần tử <img>), tôi sử dụng một phương thức đổi màu khác. Mặc dù nghiên cứu cho thấy mọi người không thích đảo ngược ảnh, nhưng việc này lại hoạt động rất hiệu quả đối với hầu hết các biểu tượng. Một lần nữa, tôi sử dụng các biến CSS để xác định mức độ đảo ngược ở trạng thái thông thường và ở trạng thái :hover.

Biểu tượng và văn bản màu trắng trên nền đen.
Biểu tượng được đảo ngược trong chế độ tối.
Biểu tượng và văn bản màu đen trên nền trắng.
Biểu tượng thông thường ở chế độ sáng.

Lưu ý cách tôi chỉ đảo ngược các biểu tượng trong dark.css chứ không phải trong light.css, và cách :hover có cường độ đảo ngược khác nhau trong hai trường hợp để biểu tượng xuất hiện tối hơn một chút hoặc sáng hơn một chút, tuỳ thuộc vào chế độ mà người dùng đã chọn.

/* dark.css */
--icon-filter: invert(100%);
--icon-filter_hover: invert(40%);

img[src*='.svg'] {
  filter: var(--icon-filter);
}
/* light.css */
--icon-filter_hover: invert(60%);
/* style.css */
img[src*='.svg']:hover {
  filter: var(--icon-filter_hover);
}

Sử dụng currentColor cho SVG nội tuyến

Đối với hình ảnh SVG nội tuyến, thay vì sử dụng bộ lọc đảo ngược, bạn có thể tận dụng từ khoá CSS currentColor. Từ khoá này đại diện cho giá trị của thuộc tính color của một phần tử. Điều này cho phép bạn sử dụng giá trị color trên những thuộc tính không nhận được giá trị này theo mặc định. Một cách thuận tiện là nếu currentColor được dùng làm giá trị của thuộc tính SVG fill hoặc stroke, thì giá trị này sẽ lấy giá trị từ giá trị được kế thừa của thuộc tính màu. Thậm chí, điều này còn hiệu quả hơn đối với <svg><use href="…"></svg>, vì vậy, bạn có thể có các tài nguyên riêng biệt và currentColor vẫn sẽ được áp dụng trong ngữ cảnh. Xin lưu ý rằng điều này chỉ hoạt động đối với SVG nội dòng hoặc <use href="…">, nhưng không hoạt động đối với SVG được tham chiếu dưới dạng src của hình ảnh hoặc bằng cách nào đó thông qua CSS. Bạn có thể thấy điều này được áp dụng trong bản minh hoạ bên dưới.

<!-- Some inline SVG -->
<svg xmlns="http://www.w3.org/2000/svg"
    stroke="currentColor"
>
  […]
</svg>

Chuyển đổi mượt mà giữa các chế độ

Bạn có thể chuyển đổi mượt mà từ chế độ tối sang chế độ sáng hoặc ngược lại nhờ thực tế là cả colorbackground-color đều là các thuộc tính CSS có thể tạo ảnh động. Bạn chỉ cần khai báo 2 transition cho 2 thuộc tính là có thể tạo được ảnh động. Ví dụ bên dưới minh hoạ ý tưởng chung, bạn có thể trải nghiệm trực tiếp trong bản minh hoạ.

body {
  --duration: 0.5s;
  --timing: ease;

  color: var(--color);
  background-color: var(--background-color);

  transition: color var(--duration) var(--timing), background-color var(
        --duration
      ) var(--timing);
}

Chỉ đạo nghệ thuật với chế độ tối

Mặc dù vì lý do hiệu suất tải, nói chung, tôi khuyên bạn chỉ nên làm việc với prefers-color-scheme trong thuộc tính media của các phần tử <link> (thay vì nội tuyến trong biểu định kiểu), nhưng có những trường hợp bạn thực sự có thể muốn làm việc trực tiếp với prefers-color-scheme nội tuyến trong mã HTML. Chỉ đạo nghệ thuật là một tình huống như vậy. Trên web, hướng nghệ thuật liên quan đến diện mạo tổng thể của một trang và cách trang đó truyền đạt thông tin bằng hình ảnh, kích thích tâm trạng, làm nổi bật các tính năng và thu hút đối tượng mục tiêu về mặt tâm lý.

Khi dùng chế độ tối, nhà thiết kế sẽ phải tự đánh giá để quyết định đâu là hình ảnh phù hợp nhất ở một chế độ cụ thể và liệu việc đổi màu hình ảnhkhông đủ tốt hay không. Nếu được dùng với phần tử <picture>, bạn có thể đặt <source> của hình ảnh sẽ xuất hiện tuỳ thuộc vào thuộc tính media. Trong ví dụ bên dưới, tôi cho thấy bán cầu Tây cho chế độ tối và bán cầu Đông cho chế độ sáng hoặc khi không có lựa chọn ưu tiên nào được đưa ra, mặc định là bán cầu Đông trong tất cả các trường hợp khác. Tất nhiên, điều này chỉ nhằm mục đích minh hoạ. Bật chế độ tối trên thiết bị để thấy sự khác biệt.

<picture>
  <source srcset="western.webp" media="(prefers-color-scheme: dark)" />
  <source srcset="eastern.webp" media="(prefers-color-scheme: light)" />
  <img src="eastern.webp" />
</picture>

Chế độ tối, nhưng thêm lựa chọn không sử dụng

Như đã đề cập trong phần lý do nên dùng chế độ tối ở trên, chế độ tối là lựa chọn thẩm mỹ đối với hầu hết người dùng. Do đó, một số người dùng có thể thích giao diện người dùng hệ điều hành ở chế độ tối, nhưng vẫn muốn xem các trang web theo cách họ thường thấy. Một mẫu hay là ban đầu tuân thủ tín hiệu mà trình duyệt gửi thông qua prefers-color-scheme, nhưng sau đó cho phép người dùng tuỳ ý ghi đè chế độ cài đặt ở cấp hệ thống.

Phần tử tuỳ chỉnh <dark-mode-toggle>

Tất nhiên, bạn có thể tự tạo mã cho việc này, nhưng bạn cũng có thể chỉ cần sử dụng một phần tử tuỳ chỉnh (thành phần web) có sẵn mà tôi đã tạo cho mục đích này. Công cụ này có tên là <dark-mode-toggle> và sẽ thêm một nút bật/tắt (chế độ tối: bật/tắt) hoặc một công cụ chuyển đổi giao diện (giao diện: sáng/tối) vào trang mà bạn có thể tuỳ chỉnh hoàn toàn. Bản minh hoạ dưới đây cho thấy phần tử này đang hoạt động (à, và tôi cũng đã 🤫 lặng lẽ đưa phần tử này vào tất cả các ví dụ ở trên).

<dark-mode-toggle
  legend="Theme Switcher"
  appearance="switch"
  dark="Dark"
  light="Light"
  remember="Remember this"
></dark-mode-toggle>
<dark-mode-toggle> ở chế độ sáng.
<dark-mode-toggle> ở chế độ tối.

Hãy thử nhấp hoặc nhấn vào các nút điều khiển chế độ tối ở góc trên cùng bên phải trong bản minh hoạ sau. Nếu bạn đánh dấu vào hộp đánh dấu ở chế độ điều khiển thứ ba và thứ tư, hãy xem cách lựa chọn chế độ của bạn được ghi nhớ ngay cả khi bạn tải lại trang. Nhờ đó, khách truy cập có thể giữ hệ điều hành ở chế độ tối nhưng vẫn có thể thưởng thức trang web của bạn ở chế độ sáng hoặc ngược lại.

Kết luận

Làm việc và hỗ trợ chế độ tối là một trải nghiệm thú vị và mở ra những hướng thiết kế mới. Đối với một số khách truy cập, điều này có thể tạo ra sự khác biệt giữa việc không thể xử lý trang web của bạn và việc trở thành một người dùng hài lòng. Có một số điểm cần lưu ý và bạn chắc chắn phải kiểm thử cẩn thận, nhưng chế độ tối chắc chắn là một cơ hội tuyệt vời để bạn thể hiện rằng bạn quan tâm đến tất cả người dùng của mình. Các phương pháp hay nhất được đề cập trong bài đăng này và các thành phần hỗ trợ như phần tử tuỳ chỉnh <dark-mode-toggle> sẽ giúp bạn tự tin vào khả năng tạo ra trải nghiệm tuyệt vời ở chế độ tối. Hãy cho tôi biết trên Twitter về nội dung bạn tạo và liệu bài đăng này có hữu ích hay không, hoặc bạn cũng có thể đề xuất cách cải thiện bài đăng. Cảm ơn bạn đã đọc! 🌒

Tài nguyên cho truy vấn nội dung nghe nhìn prefers-color-scheme:

Tài nguyên cho thẻ meta color-scheme và thuộc tính CSS:

Các đường liên kết chung về chế độ tối:

Các bài viết nghiên cứu cơ bản cho bài đăng này:

Lời cảm ơn

Tính năng đa phương tiện prefers-color-scheme, thuộc tính CSS color-scheme và thẻ meta có liên quan là thành quả triển khai của 👏 Rune Lillesveen. Rune cũng là đồng tác giả của quy cách CSS Color Adjustment Module Level 1 (Mô-đun điều chỉnh màu CSS cấp 1). Tôi xin 🙏 cảm ơn Lukasz Zbylut, Rowan Merewood, Chirag DesaiRob Dodson vì đã xem xét kỹ lưỡng bài viết này. Chiến lược tải là ý tưởng của Jake Archibald. Emilio Cobos Álvarez đã chỉ cho tôi phương pháp phát hiện prefers-color-scheme chính xác. Mẹo có các SVG được tham chiếu và currentColor là của Timothy Hatcher. Cuối cùng, tôi xin cảm ơn nhiều người tham gia ẩn danh trong các nghiên cứu về người dùng. Họ đã giúp định hình những đề xuất trong bài viết này.