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 trang của họ sử dụng chế độ mặc định theo giao diện cụ thể của biểu định kiểu tác nhân người dùng.

Tính năng nội dung đa phương tiện ưu tiên của người dùng prefers-color-scheme cho phép nhà phát triển kiểm soát toàn bộ giao diện của 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: Hello darkness, my old friend (prefers-color-scheme: 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ề việc tạo 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 CSS color-scheme và thẻ meta tương ứng có cùng tên. Cả hai đều giúp bạn dễ dàng hơn trong vai trò nhà phát triển bằng cách cho phép bạn chọn trang của mình theo các giá trị mặc định theo chủ đề cụ thể của tệp 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 bất kỳ phép biến đổi nào.

Hỗ trợ trình duyệt

prefers-color-scheme

Hỗ trợ trình duyệt

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

Nguồn

color-scheme

Hỗ trợ trình duyệt

  • Chrome: 81.
  • Cạnh: 81.
  • Firefox: 96.
  • Safari: 13.

Nguồn

Tệp biểu định kiểu của 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ề tệp biểu định kiểu tác nhân người dùng. Thông thường, bạn có thể coi từ tác nhân người dùng (UA) là một cách gọi trình duyệt. Tệp kiểu UA xác định giao diện mặc định của một trang. Như tên gọi, một tệp kiểu UA phụ thuộc vào UA có liên quan. Bạn có thể xem xét trang kiểu UA của Chrome (và Chromium) và so sánh với trang kiểu UA của Firefox hoặc Safari (và WebKit). Thông thường, các tệp kiểu của UA đều thống nhất về hầu hết các vấn đề. Ví dụ: tất cả các đường liên kết đều có màu xanh dương, văn bản chung có màu đen và màu nền trắng, nhưng cũng có những điểm khác biệt quan trọng (và đôi khi gây khó chịu), chẳng hạn như cách chúng tạo kiểu cho các chế độ điều khiển biểu mẫu.

Hãy xem xét kỹ hơn về tệp kiểu UA của WebKit và chức năng của tệp này liên quan đến chế độ tối. (Tìm kiếm toàn bộ văn bản "dark" (tối) trong tệp kiểu.) Giá trị mặc định do tệp kiểu cung cấp sẽ thay đổi dựa trên 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 sử dụng lớp giả :matches và các biến nội bộ WebKit như -apple-system-control-background, cũng như lệnh tiền xử lý nội bộ 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ẽ thấy một số giá trị không theo 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.

Hóa ra, CSS đã chuẩn hoá màu sắc ngữ nghĩa của hệ thống. Các giá trị này được chỉ định trong Mô-đun màu CSS cấp 4. Ví dụ: Canvas (đừng nhầm với thẻ <canvas>) là dành cho nền của nội dung ứng dụng hoặc tài liệu, còn CanvasText là dành cho văn bản trong nội dung ứng dụng hoặc tài liệu. Hai thành phần này đi cùng nhau và không được sử dụng riêng lẻ.

Biểu định kiểu UA có thể sử dụng màu thuộc quyền sở hữu riêng hoặc màu của hệ thống ngữ nghĩa được chuẩn hoá để xác định cách hiển thị các phần tử HTML theo mặc định. Nếu bạn đặt hệ điều hành ở chế độ tối hoặc sử dụng giao diện tối, thì CanvasText (hoặc text) sẽ được đặt thành màu trắng theo điều kiện và Canvas (hoặc -apple-system-control-background) sẽ được đặt thành màu đen. Sau đó, tệp kiểu UA chỉ gán 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

Thông số kỹ thuật Mô-đun điều chỉnh màu CSS cấp 1 giới thiệu một mô hình và kiểm soát 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 bảng phối màu cụ thể 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 giao diện màu nào phù hợp để hiển thị. Các 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 bảng phối màu được chọn sẽ ảnh hưởng đến những điều trên giao diện người dùng (UI), chẳng hạn như màu mặc định của các tuỳ chọn điều khiển biểu mẫu và thanh cuộn, cũng như giá trị đã sử dụng của màu hệ thống CSS. Các giá trị sau đây hiện được hỗ trợ:

  • normal Cho biết phần tử hoàn toàn không nhận biết bảng phối màu và vì vậy phần tử phải đượ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 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 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 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, còn 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 hiển thị bằng bảng phối màu phải khiến màu sắc dùng trong tất cả giao diện người dùng do trình duyệt cung cấp cho các phần tử đó khớp với ý định của bảng phối màu. Ví dụ: thanh cuộn, dấu gạch dưới kiểm tra lỗi chính tả, thanh điều khiển biểu mẫu, v.v.

Trên phần tử :root, việc kết xuất bằng 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 toàn cục), giá trị ban đầu của thuộc tính color và các giá trị được sử 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 nhìn.

/*
  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 phải tải CSS xuống (nếu được tham chiếu thông 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) đều dẫn đến cùng một hành vi, nên bạn luô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 bảng phối màu ưu tiên nhanh hơn.

Mặc dù đối với các trang cơ sở tuyệt đối, bạn không cần thêm quy tắc CSS nào, nhưng trong trường hợp chung, bạn phải luôn kết hợp color-scheme với prefers-color-scheme. Ví dụ: màu CSS WebKit độc quyền -webkit-link, do WebKit và Chrome sử dụng cho đường liên kết màu xanh dương cổ điển rgb(0,0,238), có tỷ lệ tương phản không đủ 2,23:1 trên nền đen và không đáp ứng cả các yêu cầu WCAG AA cũng như 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 lỗi 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 ưu tiên của người dùng prefers-color-scheme có vẻ như gây nhầm lẫn lúc đầu. Trên thực tế, chúng hoạt động rất hiệu quả với nhau. Điều quan trọng nhất cần hiểu là color-scheme xác định riêng giao diện mặc định, trong khi prefers-color-scheme xác định giao diện có thể tạo kiểu. Để làm rõ hơn, hãy giả sử 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 cùng dòng trên trang sẽ đặ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 thích bảng phối màu dark theo tính năng đa phương tiện theo lựa chọn ưu tiên của người dùng prefers-color-scheme.

Thông qua phần tử <meta name="color-scheme" content="dark light">, trang sẽ cho trình duyệt biết rằng trang này hỗ trợ giao diện tối và 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 sáng, toàn bộ trang sẽ chuyển sang chế độ sáng khi 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 nào do nhà phát triển cung cấp để thay đổi văn bản của đoạn văn bả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 trang kiểu nội tuyến do nhà phát triển cung cấp trên trang. Đó là gainsboro hoặc darkslategray.

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

Giao diện của phần tử <button> được kiểm soát bởi tệp kiểu của tác nhân người dùng. color đượ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.

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ị đã tính cho border-top-colorborder-bottom-color chuyển từ rgba(0, 0, 0, 0.847) (màu đen) sang rgba(255, 255, 255, 0.847) (màu trắng), vì tác nhân người dùng cập nhật ButtonFace một cách linh động 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 đã tính toán khớp với ButtonFace.
Chế độ sáng: Các giá trị đã tính toán của border-top-colorborder-bottom-color đều được đặt thành ButtonFace trong biểu định kiểu tác nhân người dùng giờ đây 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ị đã tính toán của border-top-colorborder-bottom-color đều được đặt thành ButtonFace trong biểu định kiểu tác nhân người dùng giờ đây 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 phần tử HTML trong bản minh hoạ trên Glitch. Bản minh hoạ cố ý cho thấy lỗi vi phạm WCAG AA và WCAG AAA bằng màu liên kết được đề cập trong cảnh báo ở trên.

Bản minh hoạ ở chế độ sáng.
Bản minh hoạ đã chuyển sang color-scheme: light.
Bản minh hoạ ở chế độ tối.
Bản minh hoạ được chuyển thành color-scheme: dark. Lưu ý lỗi vi phạm WCAG AA và WCAG AAA về 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 do Rune Lillesveen triển khai. 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). Hình ảnh chính của Philippe Leone trên Unsplash.