Cải thiện kiểu mặc định của chế độ tối bằng thuộc tính CSS phối màu và thẻ meta tương ứng

Thuộc tính CSS color-scheme và thẻ meta tương ứng cho phép nhà phát triển chọn sử dụng các giá trị mặc định dành riêng cho giao diện của biểu định kiểu tác nhân người dùng.

Thông tin khái quát

Tính năng nội dung đa phương tiện theo lựa chọn ưu tiên của người dùng prefers-color-scheme

Tính năng nội dung nghe nhìn theo lựa chọn ưu tiên của người dùng prefers-color-scheme giúp nhà phát triển có toàn quyền kiểm soát giao diện của các trang. Nếu bạn chưa quen với chế độ này, vui lòng đọc bài viết của tôi prefers-color-scheme: Xin chào bóng tối, người bạn cũ của tôi. Trong bài viết này, tôi đã ghi lại mọi điều tôi biết về cách tạo ra trải nghiệm tuyệt vời ở chế độ tối.

Một mảnh ghép chỉ được đề cập ngắn gọn trong bài viết là thuộc tính color-scheme CSS và thẻ meta tương ứng có cùng tên. Cả hai đều giúp cuộc sống của bạn trở nên dễ dàng hơn với tư cách là một nhà phát triển bằng cách cho phép bạn chọn trang của mình trong các giá trị mặc định dành riêng cho giao diện của biểu định kiểu tác nhân người dùng, chẳng hạn như các thành phần điều khiển biểu mẫu, thanh cuộn cũng như màu hệ thống CSS. Đồng thời, tính năng này ngăn trình duyệt tự áp dụng mọi quy tắc chuyển đổi.

Hỗ trợ trình duyệt

prefers-color-scheme

Browser Support

  • Chrome: 76.
  • Edge: 79.
  • Firefox: 67.
  • Safari: 12.1.

Source

color-scheme

Browser Support

  • Chrome: 81.
  • Edge: 81.
  • Firefox: 96.
  • Safari: 13.

Source

Biểu định kiểu tác nhân người dùng

Trước khi tiếp tục, hãy để tôi mô tả ngắn gọn về biểu định kiểu tác nhân người dùng. Hầu hết thời gian, bạn có thể coi từ tác nhân người dùng (UA) là một cách nói hoa mỹ của từ trình duyệt. Biểu định kiểu UA xác định giao diện mặc định của một trang. Như tên gọi cho thấy, biểu định kiểu UA là một thứ phụ thuộc vào UA được đề cập. Bạn có thể xem biểu định kiểu UA của Chrome (và Chromium) rồi so sánh với Firefox hoặc Safari (và WebKit). Thông thường, biểu định kiểu UA sẽ thống nhất về phần lớn các nội dung. Ví dụ: tất cả đều tạo đường liên kết màu xanh dương, văn bản chung màu đen và màu nền màu trắng, nhưng cũng có những điểm khác biệt quan trọng (và đôi khi gây phiền toái), chẳng hạn như cách chúng tạo kiểu cho các chế độ kiểm soát biểu mẫu.

Hãy xem xét kỹ hơn biểu định kiểu UA của WebKit và những việc mà biểu định kiểu này làm liên quan đến chế độ tối. (Tìm kiếm toàn văn "dark" trong biểu định kiểu.) Giá trị mặc định do biểu định kiểu cung cấp sẽ thay đổi tuỳ thuộc vào việc chế độ tối đang bật hay tắt. Để minh hoạ điều này, sau đây là một quy tắc CSS như vậy bằng cách sử dụng lớp giả :matches và các biến nội bộ của WebKit như -apple-system-control-background, cũng như chỉ thị tiền xử lý nội bộ của WebKit #if defined:

input,
input:matches([type="password"], [type="search"]) {
  -webkit-appearance: textfield;
  #if defined(HAVE_OS_DARK_MODE_SUPPORT) &&
      HAVE_OS_DARK_MODE_SUPPORT
    color: text;
    background-color: -apple-system-control-background;
  #else
    background-color: white;
  #endif
  /* snip */
}

Bạn sẽ nhận thấy một số giá trị không chuẩn cho các thuộc tính colorbackground-color ở trên. Cả text-apple-system-control-background đều không phải là màu CSS hợp lệ. Đây là các màu ngữ nghĩa nội bộ của WebKit.

Hoá ra, CSS đã chuẩn hoá các màu hệ thống ngữ nghĩa. Các giá trị này được chỉ định trong CSS Color Module Level 4. Ví dụ: Canvas (không nhầm lẫn với thẻ <canvas>) là cho nền của nội dung hoặc tài liệu ứng dụng, trong khi CanvasText là cho văn bản trong nội dung hoặc tài liệu ứng dụng. Hai yếu tố này đi đôi với nhau và không nên được sử dụng riêng lẻ.

Biểu định kiểu UA có thể sử dụng màu hệ thống ngữ nghĩa độc quyền hoặc tiêu chuẩn của riêng chúng để xác định cách các phần tử HTML sẽ được kết xuất theo mặc định. Nếu hệ điều hành được đặt ở chế độ tối hoặc sử dụng giao diện tối, CanvasText (hoặc text) sẽ được đặt có điều kiện thành màu trắng và Canvas (hoặc -apple-system-control-background) sẽ được đặt thành màu đen. Sau đó, biểu định kiểu UA chỉ chỉ định CSS sau đây một lần và bao gồm cả chế độ sáng và tối.

/**
  Not actual UA stylesheet code.
  For illustrative purposes only.
*/
body {
  color: CanvasText;
  background-color: Canvas
}

Thuộc tính CSS color-scheme

Quy cách CSS Color Adjustment Module Level 1 (Mô-đun điều chỉnh màu CSS cấp 1) giới thiệu một mô hình và các chế độ kiểm soát đối với việc điều chỉnh màu tự động của tác nhân người dùng với mục tiêu xử lý các lựa chọn ưu tiên của người dùng, chẳng hạn như chế độ tối, điều chỉnh độ tương phản hoặc các bảng phối màu cụ thể mà người dùng mong muốn.

Thuộc tính color-scheme được xác định trong đó cho phép một phần tử cho biết những bảng phối màu mà phần tử đó có thể hiển thị. Những giá trị này được thương lượng theo lựa chọn ưu tiên của người dùng, dẫn đến một bảng phối màu được chọn ảnh hưởng đến những thành phần trong giao diện người dùng (UI) như màu mặc định của các chế độ kiểm soát biểu mẫu và thanh cuộn, cũng như các giá trị được dùng của màu hệ thống CSS. Hiện tại, chúng tôi hỗ trợ những giá trị sau:

  • normal Cho biết rằng phần tử hoàn toàn không nhận biết được bảng phối màu, do đó, phần tử này sẽ được kết xuất bằng bảng phối màu mặc định của trình duyệt.

  • [ light | dark ]+ Cho biết rằng phần tử nhận biết và có thể xử lý các bảng phối màu được liệt kê, đồng thời thể hiện một lựa chọn ưu tiên có thứ tự giữa các bảng phối màu đó.

Trong danh sách này, light đại diện cho một bảng phối màu sáng, với màu nền sáng và màu nền trước tối, trong khi dark đại diện cho bảng phối màu ngược lại, với màu nền tối và màu nền trước sáng.

Đối với tất cả các phần tử, việc kết xuất bằng một bảng phối màu sẽ khiến các màu được dùng trong tất cả giao diện người dùng do trình duyệt cung cấp cho phần tử đó khớp với ý định của bảng phối màu. Ví dụ: thanh cuộn, đường gạch chân lỗi chính tả, chế độ kiểm soát biểu mẫu, v.v.

Trên phần tử :root, việc kết xuất bằng một bảng phối màu cũng phải ảnh hưởng đến màu bề mặt của canvas (tức là màu nền chung), giá trị ban đầu của thuộc tính color và các giá trị đã dùng của màu hệ thống, đồng thời cũng phải ảnh hưởng đến thanh cuộn của khung hiển thị.

/*
  The page supports both dark and light color schemes,
  and the page author prefers dark.
*/
:root {
  color-scheme: dark light;
}

Thẻ meta color-scheme

Để tuân thủ thuộc tính CSS color-scheme, trước tiên, bạn cần tải CSS xuống (nếu được tham chiếu qua <link rel="stylesheet">) và phân tích cú pháp. Để hỗ trợ các tác nhân người dùng hiển thị nền trang bằng bảng phối màu mong muốn ngay lập tức, bạn cũng có thể cung cấp giá trị color-scheme trong phần tử <meta name="color-scheme">.

<!--
  The page supports both dark and light color schemes,
  and the page author prefers dark.
-->
<meta name="color-scheme" content="dark light">

Kết hợp color-schemeprefers-color-scheme

Vì cả thẻ meta và thuộc tính CSS (nếu được áp dụng cho phần tử :root) cuối cùng đều dẫn đến cùng một hành vi, nên tôi luôn khuyên bạn nên chỉ định bảng phối màu thông qua thẻ meta để trình duyệt có thể áp dụng cho bảng phối màu ưu tiên nhanh hơn.

Mặc dù không cần thêm quy tắc CSS cho các trang cơ sở tuyệt đối, nhưng trong trường hợp chung, bạn luôn phải kết hợp color-scheme với prefers-color-scheme. Ví dụ: màu CSS -webkit-link độc quyền của WebKit mà WebKit và Chrome dùng cho màu xanh dương của đường liên kết cổ điển rgb(0,0,238) có tỷ lệ tương phản không đủ là 2,23:1 trên nền đen và không đáp ứng cả WCAG AA cũng như các yêu cầu của WCAG AAA.

Tôi đã mở các lỗi cho Chrome, WebKitFirefox cũng như một vấn đề meta trong Tiêu chuẩn HTML để khắc phục vấn đề này.

Tương tác với prefers-color-scheme

Sự tương tác giữa thuộc tính CSS color-scheme và thẻ meta tương ứng với tính năng đa phương tiện prefers-color-scheme theo lựa chọn ưu tiên của người dùng có thể gây nhầm lẫn lúc đầu. Trên thực tế, chúng phối hợp với nhau rất tốt. Điều quan trọng nhất cần hiểu là color-scheme chỉ xác định giao diện mặc định, trong khi prefers-color-scheme xác định giao diện có thể tạo kiểu. Để hiểu rõ hơn, hãy giả sử bạn có trang sau:

<head>
  <meta name="color-scheme" content="dark light">
  <style>
    fieldset {
      background-color: gainsboro;
    }
    @media (prefers-color-scheme: dark) {
      fieldset {
        background-color: darkslategray;
      }
    }
  </style>
</head>
<body>
  <p>
    Lorem ipsum dolor sit amet, legere ancillae ne vis.
  </p>
  <form>
    <fieldset>
      <legend>Lorem ipsum</legend>
      <button type="button">Lorem ipsum</button>
    </fieldset>
  </form>
</body>

Mã CSS nội tuyến trên trang đặt background-color của phần tử <fieldset> thành gainsboro trong trường hợp chung và thành darkslategray nếu người dùng ưu tiên một bảng phối màu dark theo tính năng đa phương tiện prefers-color-scheme về lựa chọn ưu tiên của người dùng.

Thông qua phần tử <meta name="color-scheme" content="dark light">, trang này cho trình duyệt biết rằng trang hỗ trợ giao diện tối và giao diện sáng, ưu tiên giao diện tối.

Tuỳ thuộc vào việc hệ điều hành được đặt ở chế độ tối hay chế độ sáng, toàn bộ trang sẽ xuất hiện ở chế độ sáng trên nền tối hoặc ngược lại, dựa trên biểu định kiểu tác nhân người dùng. Không có CSS bổ sung do nhà phát triển cung cấp để thay đổi văn bản đoạn hoặc màu nền của trang.

Lưu ý cách background-color của phần tử <fieldset> thay đổi dựa trên việc chế độ tối có được bật hay không, tuân theo các quy tắc trong biểu định kiểu nội tuyến do nhà phát triển cung cấp trên trang. Giá trị này là gainsboro hoặc darkslategray.

Một trang ở chế độ sáng.
Chế độ sáng: Kiểu do nhà phát triển và tác nhân người dùng chỉ định. Văn bản có màu đen và nền có màu trắng theo biểu định kiểu của tác nhân người dùng. background-color của phần tử <fieldset>gainsboro theo biểu định kiểu của nhà phát triển được nội tuyến.
Một trang ở chế độ tối.
Chế độ tối: Kiểu do nhà phát triển và tác nhân người dùng chỉ định. Văn bản có màu trắng và nền có màu đen theo biểu định kiểu của tác nhân người dùng. background-color của phần tử <fieldset>darkslategray theo biểu định kiểu của nhà phát triển được nội tuyến.

Giao diện của phần tử <button> do biểu định kiểu tác nhân người dùng kiểm soát. color của nút này được đặt thành màu hệ thống ButtonText, còn background-color và 4 border-color được đặt thành màu hệ thống ButtonFace.

Một trang ở chế độ sáng sử dụng thuộc tính ButtonFace.
Chế độ sáng: background-color và nhiều border-color được đặt thành màu hệ thống ButtonFace.

Bây giờ, hãy lưu ý cách border-color của phần tử <button> thay đổi. Giá trị được tính cho border-top-colorborder-bottom-color chuyển từ rgba(0, 0, 0, 0.847) (hơi đen) sang rgba(255, 255, 255, 0.847) (hơi trắng), vì tác nhân người dùng cập nhật ButtonFace một cách linh hoạt dựa trên bảng phối màu. Điều tương tự cũng áp dụng cho color của phần tử <button> được đặt thành màu hệ thống tương ứng ButtonText.

Cho thấy các giá trị màu được tính toán khớp với ButtonFace.
Chế độ sáng: Các giá trị được tính toán của border-top-colorborder-bottom-color (cả hai đều được đặt thành ButtonFace trong biểu định kiểu tác nhân người dùng) hiện là rgba(0, 0, 0, 0.847).
Cho thấy các giá trị màu được tính toán vẫn khớp với ButtonFace khi ở chế độ tối.
Chế độ tối: Các giá trị được tính của border-top-colorborder-bottom-color (cả hai đều được đặt thành ButtonFace trong biểu định kiểu tác nhân người dùng) hiện là rgba(255, 255, 255, 0.847).

Bản minh hoạ

Bạn có thể xem hiệu ứng của color-scheme được áp dụng cho một số lượng lớn các phần tử HTML trong bản minh hoạ trên Glitch. Bản minh hoạ này cố ý cho thấy lỗi WCAG AA và WCAG AAA với màu sắc của đường liên kết được đề cập trong cảnh báo ở trên.

Bản minh hoạ khi ở chế độ sáng.
Bản minh hoạ chuyển sang color-scheme: light.
Bản minh hoạ khi ở chế độ tối.
Bản minh hoạ được chuyển sang color-scheme: dark. Lưu ý lỗi vi phạm WCAG AA và WCAG AAA  với màu sắc của đường liên kết.

Lời cảm ơn

Thuộc tính CSS color-scheme và thẻ meta tương ứng được Rune Lillesveen triển khai. Rune cũng là đồng tác giả của quy cách Mô-đun điều chỉnh màu CSS cấp 1. Hình ảnh chính của Philippe Leone trên Unsplash.