ทำ Dark Mode แบบไม่พังด้วย CSS prefers-color-scheme
การทำ Dark Mode ที่ดีไม่ใช่การกลับสีทั้งหน้าแบบรวดเดียว แต่ต้องเริ่มจากระบบสีที่ออกแบบมาอย่างเป็นระเบียบด้วย CSS Variables ก่อน แล้วจึงใช้ prefers-color-scheme และการ override ของผู้ใช้ให้ทำงานร่วมกันอย่างถูกต้อง

ทำ Dark Mode แบบไม่พังด้วย CSS prefers-color-scheme
Dark Mode กลายเป็นมาตรฐานสำคัญของเว็บสมัยใหม่ แต่สิ่งที่หลายทีมพลาดคือการทำแบบเร่งรีบด้วยการ “กลับสีทั้งหน้า” ในครั้งเดียว ผลที่ตามมาคือรูปภาพเพี้ยน ปุ่มอ่านยาก ฟอร์มดูแปลก และคอนทราสต์ไม่ผ่านมาตรฐานการเข้าถึง
แนวทางที่ถูกต้องและดูเป็นมืออาชีพมากกว่าคือ การสร้างระบบสีด้วย CSS Variables หรือที่หลายคนเรียกว่า design tokens ก่อน จากนั้นจึงใช้ prefers-color-scheme เพื่อให้เว็บเลือกธีมตามระบบปฏิบัติการโดยอัตโนมัติ และเปิดทางให้ผู้ใช้สามารถเลือกธีมเองได้ในภายหลัง
ทำไมการกลับสีทั้งหน้าจึงทำให้เว็บพัง
การกลับสีแบบตรงไปตรงมาอาจดูเหมือนง่าย แต่ในทางปฏิบัติกลับสร้างปัญหาหลายด้าน เช่น
- รูปภาพและไอคอนบางส่วนสีเพี้ยน
- ปุ่มหรือข้อความมีคอนทราสต์ต่ำจนอ่านยาก
- ฟอร์มอย่าง
input,select,textareaหลุดธีม - ส่วนประกอบบางจุดดูไม่สัมพันธ์กัน เช่น การ์ดสว่างเกินไปแต่ตัวอักษรมืดเกินไป
Dark Mode ที่ดีจึงไม่ใช่แค่ “ทำให้พื้นหลังเป็นสีดำ” แต่ต้องออกแบบความสัมพันธ์ของสีทั้งหมดใหม่ให้เหมาะกับการอ่าน การใช้งาน และความสบายตา
เริ่มจากระบบสีด้วย CSS Variables
หัวใจสำคัญคือการกำหนดสีทั้งหมดผ่านตัวแปร CSS แทนการใส่ค่าสีตรง ๆ กระจายไปตามแต่ละ class วิธีนี้ช่วยให้เราสลับธีมได้ทั้งระบบโดยแก้เพียงค่าของตัวแปร
แนวคิดที่ควรใช้คือแยกสีเป็นคู่ ๆ เช่น
bgและfgสำหรับพื้นหลังกับข้อความหลักcardและcardTextสำหรับพื้นผิวของการ์ดกับข้อความในการ์ด- สีลิงก์ สีเส้นขอบ และสีเน้นต่าง ๆ
โครงสร้างที่แนะนำคือเริ่มจากค่าเริ่มต้นแบบ Light Mode ใน :root ก่อน เพราะรองรับได้กว้างและปลอดภัยที่สุด จากนั้นจึงเพิ่ม @media (prefers-color-scheme: dark) เพื่อสลับค่าตัวแปรสำหรับ Dark Mode
แทนที่จะเปลี่ยนสีทีละปุ่มหรือทีละหน้า เราเพียงสลับค่าของ variables ทั้งชุด ระบบก็จะเปลี่ยนธีมอย่างเป็นระเบียบและดูแลง่ายกว่าในระยะยาว
รองรับ 3 สถานะให้ครบ: Light, Dark และ User Override
ระบบธีมที่ดีควรรองรับอย่างน้อย 3 สถานะ ได้แก่
- Light Mode ตามค่าเริ่มต้น
- Dark Mode ตามค่าระบบด้วย
prefers-color-scheme - User Override หรือกรณีที่ผู้ใช้เลือกธีมเอง
แนวทางที่นิยมคือ หากผู้ใช้ยังไม่เคยเลือกธีม ให้เว็บไซต์อิงตามค่าระบบปฏิบัติการก่อน แต่ถ้าผู้ใช้กดเลือก Light หรือ Dark ด้วยตนเองแล้ว ให้ใส่ class เช่น .theme-light หรือ .theme-dark ไว้บน html และบันทึกค่าไว้ใน localStorage
จุดสำคัญมากคือ CSS ของการ override ต้องมีลำดับหรือ specificity ที่ชนะ media query ไม่เช่นนั้นบางหน้าจะย้อนกลับไปตามธีมของระบบแบบคาดไม่ถึง วิธีง่ายที่สุดคือเขียน .theme-dark และ .theme-light ไว้หลังส่วน @media
อย่าลืม color-scheme ให้เบราว์เซอร์ช่วยงาน
อีกเทคนิคที่ช่วยลดงานจุกจิกได้มากคือกำหนด
html {
color-scheme: light dark;
}
เมื่อใส่ค่านี้ เบราว์เซอร์จะช่วยปรับองค์ประกอบ native UI บางส่วนให้เข้ากับธีมมากขึ้น เช่น
inputselecttextarea- scrollbar
ผลคือเราต้องเสียเวลาแก้รายละเอียดเล็ก ๆ น้อยลง และหน้าตาโดยรวมจะกลมกลืนกับธีมมากขึ้นโดยอัตโนมัติ
รูปภาพและไอคอนคือจุดที่คนมักพลาด
แม้ระบบสีจะดีแค่ไหน แต่ถ้ารูปภาพหรือไอคอนไม่รองรับธีม เว็บก็ยังดูไม่สมบูรณ์ โดยเฉพาะไอคอนแบบ SVG ควรใช้ currentColor หรือผูกเข้ากับตัวแปรสี เพื่อให้สีของไอคอนเปลี่ยนตามธีมได้ทันทีโดยไม่ต้องเตรียมไฟล์สองชุด
สำหรับภาพพื้นหลังหรือกราเดียนต์ ควรตรวจสอบให้แน่ใจว่าคอนทราสต์ยังเพียงพอในทุกโหมด เพราะหลายครั้งพื้นหลังที่สวยใน Light Mode อาจอ่านยากมากเมื่อเปลี่ยนเป็น Dark Mode
คอนทราสต์ที่ดีทำให้ Dark Mode ใช้งานได้จริง
Dark Mode ที่ดูดีไม่ได้หมายถึงดำสนิทกับขาวสนิทเสมอไป ในทางกลับกัน งานออกแบบที่ดูพรีเมียมมักเลือกใช้
- พื้นหลังเป็น near-black แทนดำล้วน
- ตัวอักษรเป็น off-white แทนขาวล้วน
วิธีนี้ช่วยให้สบายตาและลดความแข็งของภาพรวมได้มาก นอกจากนี้ควรให้ความสำคัญกับข้อความขนาดเล็กเป็นพิเศษ เพราะเป็นจุดที่คอนทราสต์ต่ำแล้วอ่านยากที่สุด หากเป็นฟอนต์เล็กหรือบางมาก ควรหลีกเลี่ยงสีเทาอ่อนบนพื้นหลังดำสนิท
วิธีทดสอบ Dark Mode แบบมืออาชีพ
การทำธีมให้ครบไม่จบที่การเขียน CSS แต่ต้องทดสอบอย่างรอบด้านด้วย โดยควรเช็กอย่างน้อยดังนี้
- ทดสอบทั้ง 3 โหมด: ระบบเป็น Light, ระบบเป็น Dark และโหมดที่ผู้ใช้ override เอง
- ตรวจสอบฟอร์มทั้งหมด เช่น
input,placeholder,autofill, และfocus ringเพราะมักหลุดธีมบ่อย - เช็กภาพพื้นหลังและกราเดียนต์ว่าไม่ทำให้ข้อความจมหรือคอนทราสต์หาย
- เปิดใช้งาน
forced colorsหรือhigh contrastบน Windows เพื่อดูความเข้ากันได้ด้านการเข้าถึง - บนอุปกรณ์ Safari/iOS ให้ดู safe-area, สี address bar และสี selection ของข้อความเพิ่มเติม
หากต้องการทำงานเร็วขึ้น Chrome และ Edge DevTools สามารถ emulate prefers-color-scheme ได้ ทำให้สลับ Light/Dark ได้ทันทีโดยไม่ต้องเปลี่ยนธีมทั้งเครื่อง
แนวคิดที่ช่วยให้โค้ดอ่านง่ายและดูแลง่าย
โครงสร้างที่ดีควรเรียบง่ายและชัดเจน ดังนี้
- กำหนดค่าเริ่มต้นแบบ Light ใน
:root - เพิ่ม Dark Mode ผ่าน
@media (prefers-color-scheme: dark) - เพิ่ม
.theme-lightและ.theme-darkสำหรับการ override - จัดกลุ่มตัวแปรสีตามหน้าที่ ไม่กระจายแบบไร้ระบบ
เมื่อทำตามแนวทางนี้ ทีมจะสามารถขยายระบบได้ง่ายขึ้น เช่น เพิ่มธีมใหม่ ปรับ branding หรือรีแฟกเตอร์หน้าเดิมโดยไม่กระทบทั้งระบบ
สรุป
การทำ Dark Mode ให้ไม่พัง เริ่มจากการออกแบบระบบสีด้วย CSS Variables ก่อน แล้วค่อยใช้ prefers-color-scheme เพื่อสลับธีมตามระบบปฏิบัติการ จากนั้นเสริมความยืดหยุ่นด้วยการให้ผู้ใช้ override ธีมเองได้
สิ่งสำคัญคืออย่าลืมเรื่อง color-scheme, การรองรับฟอร์ม ไอคอน รูปภาพ คอนทราสต์ และการทดสอบในหลายสภาพแวดล้อม หากวางโครงสร้างตั้งแต่ต้นอย่างถูกต้อง Dark Mode จะไม่ใช่งานแก้ปัญหาเฉพาะหน้า แต่จะกลายเป็นระบบที่สวย ใช้งานง่าย และดูแลต่อได้ในระยะยาว