เข้าสู่ Dark mode ไปกับ Next.js
สมัยนี้เนี้ยอะไรๆมันก็ต้อง dark ใช่ไหมล่ะ ทั้งด้าน windows หรือ macOS เองก็มี dark mode และถ้าต่อต้านไม่ได้ก็จงเข้าร่วม !? แต่ในที่นี้ผมกำลังพูดถึงการทำให้เว็บไซต์ของเรานั้นเป็น dark mode โดยอ้างอิงจาก OS ของ user มิใช่การกดสลับจากหน้าเว็บ และถ้าพร้อมกันแล้ว เรามาพาเว็บไซต์ของเราให้เข้าสู่ DARK MODE ไปด้วยกันกับ Next.js และ styled-components
เตรียมตัวเข้าสู่ด้านมืด
ผมจะถือว่าทุกคนมี project next อยู่แล้วนะ หากใครยังไม่มีก็สามารถสร้าง project ได้ง่ายๆด้วย create-next-app และทำการติดตั้งแพคเกจ styled-components ด้วยล่ะ
Theme Objects
ก่อนอื่นเลย เราจะต้องสร้าง Theme ของเราขึ้นมาก่อน ทั้งแบบ light และ dark โดยค่าเริ่มต้นนั้นผมจะใช้เป็น light
ในตัวอย่างผมจะสร้าง theme แบบง่ายๆขึ้นมา โดยมีแค่สีของ background และ text เหตุผลที่ผมสร้างไว้แค่นี้นั้นก็เพราะว่าผม “ขี้เกียจ” ครับ
Using theme objects in ThemeProvider
style-components นั้นมีคอมโพเนนต์ที่ชื่อว่า ThemeProvider โดยเจ้า ThemeProvider จะทำให้คอมโพเนนต์(style-components) ที่เป็นอยู่ภายใต้ตัวมันสามารถเรียกใช้ค่าต่างๆของ theme ได้ผ่าน props เลย
ในตัวอย่างผมจะสร้างคอมโพเนนต์ Providers ขึ้นมาครอบเจ้า ThemeProvider อีกที ถามว่าทำไมต้องทำแบบนี้ เพราะในอนาคตอันใกล้นี้เราจะเล่นกับเจ้าคอมโพเนนต์ตัวนี้ครับ
useDarkMode Hook
สิ่งที่เรากำลังจะทำต่อจากนี้ คือตัวกำหนดว่าแอปของเรานั้นจะใช้ theme light หรือ dark โดยดูจาก OS ของ user ซึ่งจริงๆแล้วนั้นมันไม่มีอะไรมากเลยครับ เพราะปัจจุบันนี้ CSS นั้นมีความสามารถนี้อยู่แล้ว นั้นคือ prefers-color-scheme (สามารถดู browser ที่รองรับได้ที่ caniuse) เราก็แค่นำสิ่งนี้มาปรับใช้กับแอปของเรา
ในที่นี่ผมจะใช้ React Hooks โดยเจ้า Hook ของผมก็จะมีหน้าตาประมาณนี้
แต่
ประเด็นมันมีอยู่ว่า Next.js นั้นเป็น SSR(Server-Side Rendering) ทำให้ในครั้งแรกที่แอปของเราทำงานมันอยู่บน server “ให้ตายเถอะ”(เสียงน้าค่อม) !!! นั้นหมายความว่า prefers-color-scheme จะไม่สามารถรู้ได้เลยว่าฝั่ง client ที่เป็น user นั้นมีการตั้งค่า mode บน OS เป็น light หรือ dark ทำให้ครั้งแรกที่หน้าเว็บโชว์จะแสดงค่าเป็น theme default ตามที่เราได้ตั้งไว้แล้วค่อยเปลี่ยน theme อีกทีด้วยผลของ prefers-color-scheme ซึ่งนั้นส่งผลให้หน้าเว็บของเรามีการกระพริบเนื่องจากการ re-render
แต่ (2)
ทางที่จะเข้าสู่ด้านมืดนั้นเปิดอ้ารับเราอยู่เสมอ หมายความว่ามันก็ยังมีท่าดิ้นกันอยู่และท่านั้นก็คือเพื่อนเก่าของเรา visibility: hidden นั้นเองในตอนที่ฝั่ง client ได้รับหน้าเว็บของเราจาก server เราจะทำการซ่อนทั้งหมดไว้ก่อนและปล่อยให้พระเอกของเรา prefers-color-scheme ได้ทำหน้าตรวจสอบว่า user นั้นใช้ mode ใดอยู่และทำการเซตค่าให้เรียบร้อยก่อนจะโชว์หน้าเว็บของเรา นั้นเอง
Put it all together
ได้เวลานำทุกอย่างที่เราทำมาประกอบร่างแล้ว
Demo
หากใครอยากเล่นหรือดูโค้ดเต็มๆก็สามารถไป clone project ได้ที่ Github
สุดท้ายนี้
.
.
.
แสงแดดที่แยงตา ยังไม่เท่าสายตาที่แยงใจ
ขอบคุณครับ
🙏🏼 special thanks