โหมดเข้ม

พร็อพเพอร์ตี้ color-scheme จะระบุรูปแบบสี (เช่น สว่างหรือมืด) ที่หน้ารองรับ ซึ่งจะแจ้งให้เบราว์เซอร์ทราบว่าสามารถกำหนดธีมองค์ประกอบ UI แบบเนทีฟโดยอัตโนมัติ เช่น แถบเลื่อน ตัวควบคุมแบบฟอร์ม และพื้นหลัง Canvas เริ่มต้น เพื่อให้ตรงกับการออกแบบเว็บไซต์และช่วยลดแสงแฟลชสีขาวระหว่างการโหลดครั้งแรก

การใช้งาน

1. ประกาศรูปแบบที่รองรับใน HTML

บังคับ: เพื่อช่วยป้องกัน "การแสดงเนื้อหาที่ไม่มีธีมชั่วคราว" (FOUC) ให้วางแท็ก <meta> ใน <head> เพื่อให้เบราว์เซอร์ทราบว่าคุณรองรับธีมใดก่อนที่จะเริ่มแสดงผล แม้ว่าแท็ก <meta> นี้จะช่วยหลีกเลี่ยง FOUC ได้โดยการตั้งค่าสี Canvas เริ่มต้นตั้งแต่เนิ่นๆ แต่ก็อาจไม่สามารถกำจัดการกะพริบในเบราว์เซอร์หรือเงื่อนไขการโหลดทั้งหมดได้อย่างสมบูรณ์

<!-- MANDATORY: Declare support for both light and dark themes -->
<meta name="color-scheme" content="light dark">

2. ใช้รูปแบบสีทั้งหน้ากับ CSS :root หรือ html

บังคับ: ใช้พร็อพเพอร์ตี้ color-scheme กับองค์ประกอบ html หรือคลาสเทียม :root เบราว์เซอร์จะดูองค์ประกอบรูทโดยเฉพาะเพื่อกำหนดธีมสำหรับวิวพอร์ตทั้งหมด ซึ่งรวมถึงแถบเลื่อนรูทและพื้นหลัง "Canvas" เริ่มต้น หากใช้กับ body เท่านั้น พื้นผิว UI ส่วนกลางเหล่านี้อาจยังคงอยู่ในโหมดสว่างเนื่องจาก body ไม่ได้ควบคุมบริบทการแสดงผลของหน้าต่าง

/* MANDATORY: Apply color-scheme to :root or html for viewport-wide theming */
:root {
  /* MANDATORY: Automatically adapt native UI to user system preferences */
  color-scheme: light dark;
}

3. กำหนดโทเค็นสีสว่างและสีมืด

คุณสามารถใช้ฟังก์ชัน light-dark() เพื่อกำหนดโทเค็นสีที่ปรับให้เข้ากับค่า color-scheme ต่างๆ โดยอัตโนมัติ

เราขอแนะนำให้คุณเก็บค่าสีดิบไว้ในคุณสมบัติที่กำหนดเองแยกต่างหาก ซึ่งจะช่วยให้รวมค่าสีในรูปแบบต่างๆ ได้ง่ายขึ้น (และทำให้ลักษณะการทำงานสำรองง่ายขึ้น หากจำเป็น)

หากต้องการควบคุมสีของ UI ในตัว เช่น accent-color หรือ scrollbar-color ได้มากขึ้น ผู้เขียนสามารถเลือกเพิ่มสีแบบไดนามิกของตนเองได้โดยใช้คุณสมบัติที่กำหนดเองและ/หรือฟังก์ชัน light-dark() ฟังก์ชันนี้จะเลือกสีที่ถูกต้องโดยอัตโนมัติตาม color-scheme ที่คำนวณแล้วขององค์ประกอบ และไม่จำเป็นต้องใช้การค้นหาสื่อที่ซ้ำซ้อน แต่ไม่จำเป็นสำหรับการติดตั้งใช้งานขั้นพื้นฐาน

:root {
  --color-brand-light: oklch(45% 0.23 270);
  --color-brand-dark: oklch(85% 0.15 210);
  --color-brand-text-light: white;
  --color-brand-text-dark: oklch(40% 0.23 270);

  --color-brand: light-dark(var(--color-brand-light), var(--color-brand-dark));
  --color-brand-text: light-dark(var(--color-brand-text-light), var(--color-brand-text-dark));

  /* MANDATORY: Automatically adapt native UI to user system preferences */
  color-scheme: light dark;
}

button.primary {
  /* These automatically adapt to color scheme */
  background-color: var(--color-brand);
  color: var(--color-brand-text);
}

ไม่บังคับ: มีสีของระบบให้เลือกใช้จำนวนหนึ่ง ซึ่งจะปรับให้เข้ากับรูปแบบสีที่ใช้โดยอัตโนมัติ (และโหมดสีอื่นๆ เช่น สีที่บังคับ) เช่น canvas, canvastext, accentcolor (ตรวจสอบการรองรับ), buttonborder เป็นต้น โดยทั่วไปแล้ว สีเหล่านี้มีข้อจำกัดมากเกินกว่าที่จะเป็นประโยชน์ นอกเหนือจากกรณีที่เฉพาะเจาะจงมากซึ่งคุณต้องจับคู่ UI ของเบราว์เซอร์เริ่มต้นบางอย่างให้ตรงกันทุกประการ หรือใช้เป็นสีสำรอง/สีเริ่มต้น

ไม่บังคับ: ปรับแต่งคู่สีให้เหมาะกับบริบท

แม้ว่าจะลบล้างค่าเริ่มต้นของระบบ แต่การใช้คิวรี่สื่อ prefers-color-scheme เพื่อกำหนดคู่สีที่แตกต่างกันซึ่งคำนึงถึงสีของเบราว์เซอร์และ Chrome ของระบบปฏิบัติการรอบๆ หน้า (หรือของหน้าที่อยู่รอบๆ เมื่อใช้หน้าเป็น iframe) ก็อาจเป็นประโยชน์

เช่น ใช้ธีมสว่างที่มืดลงเล็กน้อยเมื่อการตั้งค่าระบบเป็น dark หรือธีมมืดที่มีคอนทราสต์มากขึ้นเมื่อการตั้งค่าระบบเป็น light เพื่อไม่ให้หน้าเว็บดูโดดเด่นกว่า UI โดยรอบมากเกินไป

การปรับแต่ง UI ของเบราว์เซอร์แบบละเอียด

การตั้งค่า color-scheme จะปรับ UI ของเบราว์เซอร์ให้เข้ากับรูปแบบสีที่ใช้แล้ว แต่จะใช้ค่าเริ่มต้นของระบบปฏิบัติการและ/หรือสีของระบบที่อาจไม่สอดคล้องกับการออกแบบเว็บไซต์อย่างสมบูรณ์ เบราว์เซอร์ที่ทันสมัยมีฮุกการปรับแต่งที่ละเอียดหลายรายการสำหรับสิ่งเหล่านี้ อย่าใช้การควบคุมแบบเนทีฟซ้ำเพียงเพื่อปรับแต่งลักษณะที่ปรากฏโดยไม่ใช้ฮุกการปรับแต่งที่เบราว์เซอร์ที่ทันสมัยมีให้จนหมด

การตั้งค่าสีเฉพาะจุด

UI ของเบราว์เซอร์บางรายการ (เช่น ช่องทำเครื่องหมายที่เลือกหรือแถบเลื่อน) จะใช้สีเฉพาะจุด ซึ่งจะเปลี่ยนเป็นค่าเริ่มต้นของการตั้งค่าระบบปฏิบัติการ แต่คุณสามารถใช้พร็อพเพอร์ตี้ accent-color เพื่อตั้งค่าเป็นสีที่สอดคล้องกับหน้าเว็บได้ดีขึ้น เช่น สีของแบรนด์ของหน้าเว็บ

html {
  accent-color: light-dark(var(--color-accent-light), var(--color-accent-dark));
}

ปัญหาที่ควรทราบเมื่อใช้ accent-color

การแสดงผล accent-color ของเบราว์เซอร์จะแตกต่างกันไป สำหรับตัวบ่งชี้ที่มักจะวาดทับพื้นหลังสีเฉพาะจุด เช่น เครื่องหมายช่องทำเครื่องหมายและจุดปุ่มตัวเลือก เบราว์เซอร์อาจใช้การดำเนินการที่แตกต่างกัน ดังนี้

  • โดยทั่วไป Chromium และ Firefox จะเลือกสีตัวบ่งชี้ที่ตัดกัน
  • Safari อาจคงตัวบ่งชี้สีขาวไว้ในโหมดสว่างหรือตัวบ่งชี้สีดำในโหมดมืดแทน ขณะที่แก้ไขสีเฉพาะจุดด้านหลัง การปรับนี้ไม่ได้ให้คอนทราสต์ที่เพียงพอสำหรับทุกสีที่ระบุเสมอไป ดังนั้นให้ทดสอบชุดค่าผสมที่สำคัญใน Safari ซึ่งรวมถึงรูปแบบสีทั้งสว่างและมืด อย่าคิดว่า Safari จะเลือกสีตัวบ่งชี้ที่ให้คอนทราสต์ที่ดีที่สุดโดยอัตโนมัติ

สีของแถบเลื่อน

คุณสามารถใช้ scrollbar-color ร่วมกับ light-dark() เพื่อตั้งค่าสีแถบเลื่อนที่กำหนดเองซึ่งปรับให้เข้ากับรูปแบบสีที่ใช้ได้

:root {
  --color-scrollbar-track: light-dark(#eee, #222);
  --color-scrollbar-thumb: light-dark(#999, #666);
  scrollbar-color: var(--color-scrollbar-thumb) var(--color-scrollbar-track);
}

ปัญหาที่ควรทราบเมื่อใช้ scrollbar-color

  • ห้ามใส่ภาพเคลื่อนไหวหรือการเปลี่ยนภาพให้กับ scrollbar-color ข้อบกพร่องของ WebKit ทำให้แถบเลื่อนกะพริบทุกครั้งที่ scrollbar-color มีการเปลี่ยนแปลง
  • ใน macOS ระบบจะละเว้นพร็อพเพอร์ตี้ scrollbar-color (มาตรฐาน) และ ::-webkit-scrollbar (เดิม) โดยค่าเริ่มต้น เนื่องจาก macOS ใช้แถบเลื่อน "วางซ้อน" แบบเนทีฟ คุณต้องจับคู่สีแบบกำหนดเองกับ scrollbar-width (เช่น thin หรือ auto) เพื่อบังคับให้ macOS แสดงผลสีเหล่านั้น
  • แม้ว่าจะใช้ scrollbar-width แล้ว แต่แถบเลื่อนแบบวางซ้อนของ macOS จะแสดงผลแทร็ก (ราง) เป็นแบบโปร่งใสโดยค่าเริ่มต้น หากการออกแบบกำหนดให้ต้องมีสีพื้นหลังของแทร็กที่มองเห็นได้ใน MacOS คุณต้องใช้ scrollbar-gutter: stable; กับคอนเทนเนอร์ที่เลื่อนได้ แต่โปรดทราบว่าสีพื้นหลังจะปรากฏหลังจากที่ผู้ใช้วางเมาส์เหนือแถบเลื่อนเท่านั้น
  • แม้จะใช้ scrollbar-gutter: stable แทร็กก็อาจโปร่งใสใน MacOS Thumb ไม่ควรขึ้นอยู่กับสีของแทร็กเพื่อให้มองเห็นได้

การปรับแต่งเพิ่มเติม

UI ของเบราว์เซอร์ส่วนใหญ่จะแสดงองค์ประกอบจำลองเพื่อปรับแต่งลักษณะที่ปรากฏได้อย่างเต็มที่ เช่น

  • ::placeholder
  • ::spelling-error
  • ::grammar-error
  • ::selection
  • ::search-text
  • ::target-text
  • ::file-selector-button

คุณสามารถใช้สี light-dark() กับองค์ประกอบเหล่านี้เพื่อใช้สีที่ปรับให้เข้ากับรูปแบบสีที่ใช้

4. รูปภาพที่แตกต่างกันสำหรับโหมดสว่างและโหมดมืด

สำหรับรูปภาพ CSS คุณยังใช้ light-dark() เพื่อระบุค่ารูปภาพที่แตกต่างกันได้ด้วย

สำคัญ: ค่าทั้ง 2 ค่าใน light-dark() ต้องเป็นประเภทเดียวกัน คุณไม่สามารถรวมสีเข้ากับรูปภาพได้ หากค่าใดค่าหนึ่งต้องเป็นรูปภาพ ให้ใช้ image(<color>) เพื่อรวมค่าสี

การตรวจจับธีมที่ใช้ JS

การแยกรูปแบบสีส่วนใหญ่ควรทำใน CSS ซึ่งจะปรับให้เข้ากับการเปลี่ยนแปลงโดยอัตโนมัติ

การอ่าน JS matchMedia("(prefers-color-scheme: dark)").matches จะต้องจัดการเหตุการณ์ change ด้วย เนื่องจากค่ากำหนดของระบบอาจเปลี่ยนแปลงได้ทุกเมื่อ

ไม่บังคับ: การใช้ปุ่มสลับรูปแบบสี

หากต้องการอนุญาตให้ผู้ใช้ลบล้างค่าเริ่มต้นของระบบสำหรับเว็บไซต์นี้ด้วยตนเอง คุณสามารถใช้ปุ่มเปิด/ปิดโหมดมืดได้ เว็บไซต์ส่วนใหญ่ไม่จำเป็นต้องมีปุ่มเปิด/ปิดแบบถาวรใน UI ของเว็บไซต์ โดยปกติแล้ว การใช้รูปแบบสีของระบบเป็นค่าเริ่มต้นก็เพียงพอแล้ว โดยอาจมีตัวเลือกการตั้งค่าในแพลตฟอร์มการตั้งค่าแยกต่างหาก ดูปุ่มเปิด/ปิดโหมดมืดเพื่อดูแนวทางปฏิบัติแนะนำเกี่ยวกับการใช้ปุ่มเปิด/ปิดโหมดมืด (ถาวรหรือไม่)

ไม่บังคับ: การลบล้างเฉพาะคอมโพเนนต์

คุณสามารถลบล้างธีมส่วนกลางสำหรับองค์ประกอบที่เฉพาะเจาะจงได้โดยตั้งค่า color-scheme ในองค์ประกอบเหล่านั้น

ดูข้อมูลเพิ่มเติมและข้อควรระวังได้ที่ธีมสว่าง/มืดเฉพาะคอมโพเนนต์

ปัญหาที่ทราบซึ่งควรคำนึงถึง

ปัญหาที่ควรทราบเมื่อใช้รูปแบบสี

  • Chrome และ Firefox จะใช้ color-scheme สำหรับ iframe โดยจะแสดงผลหน้าที่ฝังในรูปแบบสีที่ถูกต้องและปรับการค้นหาสื่อ prefers-color-scheme ของหน้าที่ฝังเพื่อแสดง color-scheme ของบริบทการฝัง แต่ Safari ไม่รองรับ และจะแปลง prefers-color-scheme เป็นการตั้งค่าระบบแม้จะอยู่ภายใน iframe
    • หากคุณควบคุมทั้งระดับบนสุดและ iframe: ให้ส่งรูปแบบสีของระดับบนสุดไปยัง iframe อย่างชัดเจนผ่านพารามิเตอร์ของ URL (?theme=dark) ณ เวลาที่สร้าง iframe หรือผ่าน postMessage() (ซึ่งช่วยให้คุณตอบสนองต่อการเปลี่ยนแปลงรันไทม์ได้ด้วย) ใน iframe ให้ตั้งค่าคลาสใน <html> (และ/หรือ color-scheme ใน :root) จากสัญญาณนั้นแทนที่จะใช้ prefers-color-scheme
    • หากคุณควบคุมเฉพาะหน้าที่ฝัง: ไม่มีวิธีที่เชื่อถือได้ในการตรวจหา color-scheme ของบริบทการฝังจากภายใน iframe ใน Safari แสดงพารามิเตอร์ธีมที่ชัดเจนใน API การฝัง (เช่น สตริงการค้นหาหรือโปรโตคอล postMessage) และจัดทำเอกสารสำหรับผู้ฝัง

กลยุทธ์สำรอง

การรองรับรูปแบบสีของเบราว์เซอร์และโหมดสำรอง

พร็อพเพอร์ตี้ color-scheme เป็นการเพิ่มประสิทธิภาพแบบต่อเนื่อง เบราว์เซอร์ที่ไม่รองรับจะละเว้นพร็อพเพอร์ตี้นี้และใช้ UI โหมดสว่างเริ่มต้น

หากต้องการปรับให้เข้ากับค่ากำหนดของผู้ใช้ในเบราว์เซอร์รุ่นเก่า ให้ใช้คิวรี่สื่อ prefers-color-scheme เพื่อแสดงสีที่แตกต่างกันเมื่อผู้ใช้ต้องการใช้โหมดมืด

  • ควรใช้การค้นหาสื่อเพื่อสลับคุณสมบัติที่กำหนดเองใน :root หรือ html
  • หลีกเลี่ยงการใช้การค้นหาสื่อในคอมโพเนนต์แต่ละรายการ เว้นแต่คอมโพเนนต์นั้นจะต้องมีการปรับแต่งโหมดมืดที่เฉพาะเจาะจงมากนอกเหนือจากสี
:root {
  /* Define brand colors for each mode */
  --color-brand-light: #0056b3;
  --color-brand-dark: #00e5ff;
  --color-brand: var(--color-brand-light);

  /* MANDATORY: Fallback for browsers without light-dark support */
  @media (prefers-color-scheme: dark) {
    --color-brand: var(--color-brand-dark);
  }

  /* Ignored in older browsers */
  color-scheme: light dark;
}

button.primary {
    background-color: var(--color-brand);
}

การสนับสนุนเบราว์เซอร์และทางเลือกสำรองสำหรับ light-dark()

สำหรับเบราว์เซอร์ที่รองรับ color-scheme แต่ยังไม่รองรับ light-dark() ควรกำหนดเวอร์ชันสีอ่อนและสีเข้มเป็นคุณสมบัติที่กำหนดเองก่อน และควรใช้มีเดียคิวรี prefers-color-scheme เพื่อตั้งค่าสีสำหรับโหมดที่เกี่ยวข้อง ดังตัวอย่างด้านล่าง

:root {
  /* Define browser UI accent color for each mode */
  --brand-accent-light: #0056b3;
  --brand-accent-dark: #00e5ff;
  --accent-color: var(--brand-accent-light);

  /* MANDATORY: Fallback for browsers without light-dark support */
  @media (prefers-color-scheme: dark) {
    --accent-color: var(--brand-accent-dark);
  }

  /* OPTIONAL: use light-dark() for more control of built-in UI colors */
  @supports (color: light-dark(white, black)) {
    --accent-color: light-dark(var(--brand-accent-light), var(--brand-accent-dark));
  }

  /* MANDATORY: Automatically adapt native UI to user system preferences */
  color-scheme: light dark;

  /* Example inherited color property */
  accent-color: var(--accent-color);
}

pre, code {
  color-scheme: dark;

  /* **Mandatory**: any inherited color properties must be set again, even if to the same design tokens */
  accent-color: var(--accent-color);
}

การรองรับเบราว์เซอร์และทางเลือกสำรองสำหรับค่ารูปภาพ light-dark()

สำหรับเบราว์เซอร์ที่ไม่รองรับ light-dark() สำหรับรูปภาพ ให้ใช้ image-set() เป็นสวิตช์ โดยกำหนด type() ให้กับแต่ละตัวเลือกจากคุณสมบัติที่กำหนดเอง และตั้งค่าตัวเลือกที่ไม่ได้ใช้งานเป็นประเภท MIME ที่ไม่รองรับเพื่อให้เบราว์เซอร์ทิ้งตัวเลือกนั้น ตัวเลือกที่ใช้งานอยู่จะได้รับค่าว่าง ดังนั้นจึงเป็นตัวเลือก image-set() ธรรมดาที่ไม่มี type()

กำหนดสวิตช์ 1 ครั้งใน :root จากนั้นเว็บไซต์ที่ใช้ทุกแห่งจะต้องมีรูปภาพทั้ง 2 รูปในบรรทัด เช่น light-dark()

:root {
  --light-type: ;
  --dark-type: type("image/do-not-use");

  /* MANDATORY: Fallback for browsers without light-dark() image support */
  @media (prefers-color-scheme: dark) {
    --light-type: type("image/do-not-use");
    --dark-type: ;
  }
}

.hero {
  background-image: image-set(url(hero-light.png) var(--light-type), url(hero-dark.png) var(--dark-type));

  @supports (background-image: light-dark(url("a"), url("b"))) {
    background-image: light-dark(url(hero-light.png), url(hero-dark.png));
  }
}
  • ระบบจะดาวน์โหลดเฉพาะรูปภาพที่เลือกเท่านั้น
  • ความละเอียดที่ยังใช้งานได้: image-set(url(a-1x.png) 1x var(--light-type), url(a-2x.png) 2x var(--light-type), url(b-1x.png) 1x var(--dark-type), url(b-2x.png) 2x var(--dark-type))
  • อย่าใช้ type("") สำหรับตัวเลือกที่ใช้งานอยู่ เบราว์เซอร์จะถือว่าสตริงว่างไม่รองรับและทิ้งทุกตัวเลือก
  • สวิตช์จะไม่เป็นไปตาม color-scheme ที่ตั้งค่าไว้ในโครงสร้างย่อย ซึ่งต่างจาก light-dark() การสลับด้วยตนเองหรือโครงสร้างย่อยที่ตั้งค่า color-scheme ต้องสลับ --light-type และ --dark-type ด้วย

ทางเลือก: คุณสมบัติที่กำหนดเอง 1 รายการต่อรูปภาพ

วิธีนี้จะง่ายกว่าเมื่อมีรูปภาพที่แตกต่างกันเพียงไม่กี่รูป แต่รูปภาพทุกรูปต้องมีสาขา Media Query ของตัวเอง และต้องสลับแต่ละรูปด้วยตนเอง

:root {
  --hero-image: url(hero-light.png);

  @media (prefers-color-scheme: dark) {
    --hero-image: url(hero-dark.png);
  }

  @supports (background-image: light-dark(url("a"), url("b"))) {
    --hero-image: light-dark(url(hero-light.png), url(hero-dark.png));
  }
}

.hero {
  background-image: var(--hero-image);
}

การสนับสนุนเบราว์เซอร์และทางเลือกสำรองสำหรับ image()

ใช้การไล่ระดับสีที่มีจุดสีเดียวและไม่มีตำแหน่ง เช่น linear-gradient(blue)

หากต้องการให้เบราว์เซอร์รองรับได้กว้างขึ้น คุณสามารถระบุตำแหน่ง 0 100% สำหรับจุดสีเดียวอย่างชัดเจน เช่น linear-gradient(blue 0 100%)

การรองรับเบราว์เซอร์และทางเลือกสำหรับ scrollbar-color

ฟีเจอร์นี้เป็นการเพิ่มประสิทธิภาพแบบต่อเนื่องและไม่จำเป็นต้องใช้กลยุทธ์สำรองเสมอไป

หากการจัดรูปแบบมีความสำคัญและเป้าหมาย Baseline ของผู้ใช้คือ "Baseline ที่พร้อมใช้งานในวงกว้าง" หรือเก่ากว่า คุณควรใส่องค์ประกอบเทียม ::-webkit-scrollbar ที่ไม่ใช่มาตรฐานเป็นทางเลือกสำรอง

รวมการใช้ CSS แบบเดิมไว้ในบล็อก @supports not (scrollbar-color: auto) เพื่อป้องกันความขัดแย้งระหว่างพร็อพเพอร์ตี้มาตรฐานกับตัวเลือก WebKit แบบเดิมในเบราว์เซอร์ที่รองรับทั้ง 2 แบบโดยค่าเริ่มต้น

หากคุณใช้คุณสมบัติที่กำหนดเองเพื่อกำหนดสี คุณสมบัติเหล่านี้จะเรียงซ้อนไปยังตัวเลือก WebKit เดิมโดยอัตโนมัติ คุณไม่จำเป็นต้องทำซ้ำ

/* Legacy fallback for WebKit/Blink browsers */
@supports not (scrollbar-color: auto) {
  .scroller::-webkit-scrollbar {
    /* Must define base size in WebKit for custom colors to be visual */
    width: 12px;
    height: 12px;
  }

  .scroller::-webkit-scrollbar-thumb {
    background: var(--scrollbar-thumb);
  }

  .scroller::-webkit-scrollbar-track {
    background: var(--scrollbar-track);
  }
}

การสำรองและการรองรับเบราว์เซอร์สำหรับ accent-color

พร็อพเพอร์ตี้ accent-color เป็นการเพิ่มประสิทธิภาพแบบต่อเนื่อง เบราว์เซอร์ที่ไม่รองรับพร็อพเพอร์ตี้นี้จะละเว้นและใช้สี UI เริ่มต้น