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 điều cần thiết? Tìm hiểu mọi thông tin 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 bật Chế độ tối

Một chiếc máy tính cũ, trước thập niên 90, hiển thị văn bản màu xanh lục trên nền đen.
Màn hình xanh lục (Nguồn)

Chúng ta đã tìm hiểu toàn bộ về chế độ tối. Vào thời kỳ đầu của máy tính cá nhân, chế độ tối không phải là một 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 chùm tia điện tử vào màn hình lân quang và phốt pho được sử dụng trong các CRT đời đầu có màu xanh lục. Vì văn bản được 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 các mẫu này thường được gọi là màn hình xanh lục.

Màn hình máy tính hiển thị phiên bản Microsoft Word trên Windows 3.1.
Tối trên nền trắng (Nguồn)

Màn hình CRT màu được giới thiệu sau đó hiển thị nhiều màu thông qua việc sử dụng phốt pho đỏ, 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ả ba chất lân quang. Với sự ra đời của WYSIWYG (What You See Is What You Get – Thấy gì được nấy) tinh vi hơn, xuất bản trên máy tính, ý tưởng làm cho tài liệu ảo giống như một tờ giấy vật lý đã trở nên phổ biến.

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

Đây là nơi xu hướng thiết kế chữ tối trên nền trắng bắt đầu, 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, 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 được tạo ra, 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 màu trên nền sáng, một giả định cơ sở cũng được cố định giá trị trong mã trong biểu định kiểu tác nhân người dùng, bao gồm cả Chrome.

Dùng điện thoại di động trên giường

Thời của màn hình CRT đã qua từ lâu. Việc sử dụng 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 đã tạo ra các kiểu sử dụng mới. Các hoạt động giải trí như duyệt web, lập trình cho vui và chơi trò chơi cao cấp thường diễn ra sau giờ làm việc trong môi trường thiếu sáng. Mọi người thậm chí còn thích dùng thiết bị trên giường vào ban đêm. Càng nhiều người dùng thiết bị trong bóng tối, thì ý tưởng quay lại với giao diện 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 tại 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 thanh lịch 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õ: "Việc chọn bật giao diện sáng hay tối là một lựa chọn mang tính 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 Mac OS 7 với 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

Cũng 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, có nút bật/tắt cho Đen trên nền trắng và 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.

Các phương thức 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 về 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 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ị giác máy tính, còn được gọi là Mỏi mắt do thiết bị kỹ thuật số, được định nghĩa là "sự kết hợp củ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 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ử)." Có ý kiến cho 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, làm tăng nguy cơ rút ngắn thời lượng ngủ, kéo dài thời gian đi vào giấc ngủ và tăng tình trạng thiếu ngủ. Ngoài ra, theo nghiên cứu của Rosenfield, 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ủ, đồng thời 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 làm 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 rực rỡ hoặc ánh sáng không đều nói chung thông qua 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 Google phổ biến như YouTube đã cho thấy mức tiết kiệm điện năng có thể lên đến 60%. Video dưới đây cung cấp thêm thông tin chi tiết về các nghiên cứu điển hình này và mức tiết kiệm điện năng cho mỗi ứng dụng.

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

Giờ đây, khi đã tìm hiểu lý do chế độ tối lại quan trọng với nhiều người dùng, hãy cùng xem 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 tuỳ chọn để kích hoạt chế độ này trong phần cài đặt. Trên macOS X, chế độ này nằm trong phần General (Chung) của lựa chọn ưu tiên về hệ thống và được gọi là Appearance (Giao diện) (ảnh chụp màn hình). Trên Windows 10, chế độ này nằm trong phần Colors (Màu sắc) và được gọi là Choose your color (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 Display (Màn hình) dưới dạng nút chuyển Dark Theme (Giao diện tối) (ảnh chụp màn hình). Còn trên iOS 13, bạn có thể thay đổi Appearance (Giao diện) trong phần Display & Brightness (Màn hình và độ sáng) của phần cài đặt (ảnh chụp màn hình).

Truy vấn đa phương tiện prefers-color-scheme

Một lý thuyết cuối cùng trước khi tôi bắt đầu. Truy vấn phương tiện cho phép tác giả kiểm tra 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ị. Các truy vấn này được dùng trong quy tắc @media của CSS để áp dụng kiểu cho tài liệu theo điều kiện, cũng như trong nhiều bối cảnh và ngôn ngữ khác, chẳng hạn như HTML và JavaScript. Truy vấn phương tiện cấp 5 giới thiệu các tính năng phương tiện theo lựa chọn ưu tiên của người dùng, tức là cách để các trang web phát hiện cách hiển thị nội dung mà người dùng ưu tiên.

Tính năng đa phương tiện prefers-color-scheme được dùng để phát hiện xem người dùng đã yêu cầu trang sử dụng giao diện màu sáng hay tối. Thuộc tính 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 có 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ọ thích 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 truy vấn đa phương tiệ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 đa phương tiệ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 đa phương tiệ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, prefers-color-scheme được hỗ trợ trên cả máy tính và thiết bị di động (nếu có) bằng Chrome và Edge kể từ phiên bản 76, Firefox kể từ phiên bản 67, và Safari kể từ phiên bản 12.1 trên macOS và kể 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ề 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 đề Client Hints Sec-CH-Prefers-Color-Scheme cho phép các trang web lấy lựa chọn ưu tiên về bảng phối màu của người dùng (không bắt buộc) tại thời điểm yêu cầu, cho phép máy chủ chèn CSS phù hợp và do đó tránh được tình trạng nhấp nháy chủ đề màu sắc 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ế. Cũng giống như 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 điều này? Vì điều 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. Do đó, để tối ưu hoá tốc độ tải, tôi đã chia CSS cho ứng dụng mẫu (cho thấy các đề xuất sau đây trong thực tế) thành 3 phần để trì 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.

Đang tải chiến lược

Hai tệp sau, light.css và dark.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ý linh độ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 cùng dòng nhỏ (sáng là một lựa chọn tuỳ ý, tôi cũng có thể đặt tối làm trải nghiệm dự phòng mặc định). Để tránh nội dung không có kiểu hiển thị nhanh, 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" />

Kiến trúc biểu định kiểu

Tôi tận dụng tối đa biến CSS, điều này cho phép style.css chung của tôi trở nên chung chung, và tất cả các tuỳ chỉnh chế độ sáng hoặc chế độ tối đều diễn ra trong hai tệp khác là dark.css và light.css. Dưới đây là một đoạn trích về các kiểu thực tế, nhưng chỉ cần như vậy là đủ để truyền tải ý tưởng tổng thể. Tôi khai báo hai biến, -⁠-⁠color và -⁠-⁠background-color, về cơ bản sẽ tạo ra một giao diện cơ sở tối trên nền sáng và một giao diện cơ sở 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, tôi sử dụng các biến này trong quy tắc body { … }. Vì được xác định trên lớp giả CSS :root (một bộ chọn trong HTML đại diện cho phần tử <html> và giống hệt với bộ chọn html, ngoại trừ việc có độ đặc hiệu cao hơn), nên các biến này sẽ xếp tầng xuống, 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 mã mẫu ở trên, có thể bạn đã nhận thấy thuộc tính color-scheme có giá trị được phân tách bằng dấu cách light dark.

Thao tác này cho trình duyệt biết chủ đề màu sắc 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 rất hữu ích, chẳng hạn như cho phép trình duyệt hiển thị các trường biểu mẫu với nền tối và văn bản sáng, điều chỉnh thanh cuộn, hoặc để bật màu đánh dấu nhận biết chủ đề. 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).

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ẽ giúp ích rất nhiều khi 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 là -⁠-⁠accent-color, vì "màu 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 bản minh hoạ được nhúng 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 nêu trên vào thực tế. Hãy thử bật/tắt chế độ tối trong chế độ cài đặt của hệ điều hành cụ thể và xem trang phản ứng như thế nào.

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

Khi thử ví dụ này, bạn có thể thấy lý do tôi tải dark.css và light.css thông qua truy vấn phương tiện. Hãy thử bật/tắt chế độ tối và 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 các tài nguyên mà trang web cần ngay bây giờ.

Sơ đồ tải mạng cho thấy cách tải CSS của chế độ tối ở chế độ sáng với mức độ ưu tiên thấp nhất.
Trang web ở chế độ sáng tải CSS của 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 của 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 của chế độ sáng với mức độ ưu tiên thấp nhất.
Sơ đồ tải mạng cho thấy cách tải CSS của chế độ 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 ứng với các thay đổi về chế độ tối

Giống như mọi thay đổi khác về truy vấn phương tiện, bạn có thể đăng ký nhận thông tin về các thay đổi đối với chế độ tối thông qua JavaScript. Bạn có thể sử dụng thuộc tính này để thay đổi linh động biểu tượng trang web 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 cách hoạt động của tính năng này. Để xem các thay đổi về màu 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 đa phương tiệ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ẫu đầu tiên khớp với yêu cầu. 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, bạn không thể xác định các thuộc tính đó trong tệp kê khai. Xem vấn đề GitHub w3c/manifest#975.

<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à thử nghiệm chế độ tối

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

Việc chuyển đổi bảng phối màu của toàn bộ hệ điều hành có thể nhanh chóng gây phiền toái, 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 tuỳ chọn Mô phỏng prefers-color-scheme của tính năng đa phương tiện 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 CSS prefers-color-scheme&quot; nằm trong thẻ Hiển thị 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 qua Giao thức Công cụ cho nhà phát triển. 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ủa 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

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. Thay vào đó, để tránh bị loá và nhoè so với nội dung tối xung quanh, tôi chọn màu trắng tối hơn một chút. Một câu lệnh như rgb(250, 250, 250) sẽ 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ỉ giao diện chính đã thay đổi từ tối trên sáng thành sáng trên tối, mà hình ảnh chính cũng trông hơi khác. Nghiên cứu về người dùng của tôi cho thấy phần lớn những người được khảo sát thích hình ảnh ít rực rỡ và ít sáng hơn một chút khi chế độ tối đang hoạt động. Tôi gọi đây là tô màu lại.

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

Bạn có thể đổi màu bằng bộ lọc CSS trên hình ảnh. Tôi sử dụng một bộ chọn CSS khớp với tất cả hình ảnh không có .svg trong URL, với ý tưởng là tôi có thể áp dụng cách xử lý màu khác cho đồ họa vectơ (biểu tượng) so với hình ảnh (ảnh chụp), thông tin chi tiết về vấn đề này có trong đoạn tiếp theo. Lưu ý rằng tôi lại sử dụng một 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 trong chế độ tối, tức là khi dark.css đang hoạt động, nên không có quy tắc tương ứng 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

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

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, chúng đượ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 màu cho ảnh, nhưng tính năng này 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 ở 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 ý rằng một lần nữa, tôi chỉ đảo ngược biểu tượng trong dark.css chứ không phải trong light.css, và cách :hover nhận được cường độ đảo ngược khác nhau trong hai trường hợp để làm cho 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 cùng dòng

Đố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 đại diện cho giá trị của thuộc tính color của một phần tử. Nhờ đó, bạn có thể sử dụng giá trị color trên các thuộc tính không nhận giá trị này theo mặc định. Thuận tiện hơn, nếu currentColor được dùng làm giá trị của fill hoặc stroke thuộc tính của SVG, thì giá trị này sẽ lấy giá trị từ giá trị kế thừa của thuộc tính màu. Thậm chí, cách này còn hiệu quả với <svg><use href="…"></svg>, nên 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 bối cảnh. Xin lưu ý rằng tính năng này chỉ hoạt động đối với SVG nội tuyến 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ể xem cách á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ế độ

Việc chuyển đổi từ chế độ tối sang chế độ sáng hoặc ngược lại có thể diễn ra mượt mà nhờ vào việc cả color và background-color đều là các thuộc tính CSS có thể tạo ảnh động. Việc tạo ảnh động cũng dễ dàng như việc khai báo hai transition cho hai thuộc tính. Ví dụ dưới đây minh hoạ ý tưởng tổng thể, 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, tôi thường khuyên bạn chỉ nên làm việc với prefers-color-scheme trong thuộc tính media của phần tử <link> (thay vì cùng dòng trong biểu định kiểu), nhưng có những trường hợp bạn thực sự muốn làm việc trực tiếp với prefers-color-scheme cùng dòng trong mã HTML. Chỉ đạo nghệ thuật là một tình huống như vậy. Trên web, chỉ đạo nghệ thuật liên quan đến giao diện hình ảnh tổng thể của một trang và cách trang đó giao tiếp bằng hình ảnh, kích thích tâm trạng, tương phản các tính năng và thu hút đối tượng mục tiêu về mặt tâm lý.

Với chế độ tối, nhà thiết kế sẽ quyết định hình ảnh nào là phù hợp nhất ở một chế độ cụ thể và liệu việc đổi màu hình ảnh có không đủ tốt hay không. Nếu được dùng với phần tử <picture>, thì <source> của hình ảnh sẽ hiển thị có thể phụ 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 ở chế độ tối và bán cầu Đông ở chế độ sáng hoặc khi không có lựa chọn ưu tiên nào, 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, đây chỉ là ví dụ minh hoạ. Bật/tắt chế độ tối trên thiết bị để xem 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 tham gia

Như đã đề cập trong phần lý do nên dùng chế độ tối ở trên, chế độ tối là một lựa chọn mang tính 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ực sự muốn giao diện người dùng của hệ điều hành ở chế độ tối, nhưng vẫn muốn xem các trang web theo cách họ quen thuộc. Một mẫu hay là ban đầu tuân thủ tín hiệu mà trình duyệt gửi qua prefers-color-scheme, nhưng sau đó cho phép người dùng ghi đè chế độ cài đặt ở cấp hệ thống (không bắt buộc).

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) tạo sẵn mà tôi đã tạo cho mục đích này. Thành phần này có tên là <dark-mode-toggle> và thêm một nút bật/tắt (chế độ tối: bật/tắt) hoặc một nút chuyển đổi giao diện (giao diện: sáng/tối) vào trang của bạn 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 hoạt động (ồ, và tôi cũng đã 🤫 lén lút đưa phần tử này vào tất cả ví dụ khác ở 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 bên phải trong bản minh hoạ sau. Nếu bạn đánh dấu vào hộp đánh dấu trong 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. Điều này cho phép khách truy cập giữ hệ điều hành của họ ở chế độ tối, nhưng tận hưởng trang web của bạn ở chế độ sáng hoặc ngược lại.

Kết luận

Việc làm việc và hỗ trợ chế độ tối rất 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 cho thấy 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 trình trợ giúp 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 chế độ tối tuyệt vời. Hãy cho tôi biết trên Twitter về những gì 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ể đưa ra đề xuất để cải thiện bài đăng này. Cảm ơn bạn đã đọc thư! 🌒

Tài nguyên cho truy vấn đa phương tiện prefers-color-scheme:

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

Đườ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:

Xác nhận

Tính năng đa phương tiện prefers-color-scheme, thuộc tính CSS color-scheme và thẻ meta liên quan là công việc triển khai của 👏 Rune Lillesveen. Rune cũng là đồng biên tập của thông số kỹ thuật CSS Color Adjustment Module Level 1 (Mô-đun điều chỉnh màu CSS cấp 1). Tôi muốn 🙏 cảm ơn Lukasz Zbylut, Rowan Merewood, Chirag Desai, và Rob 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 thức phát hiện prefers-color-scheme chính xác. Mẹo về 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 người dùng khác nhau đã giúp định hình các đề xuất trong bài viết này.