Introduction
Dark Mode hay còn gọi là chế độ nền tối, về cơ bản, chế độ này sẽ chuyển đổi nền sáng (mặc định) sang nền có màu chủ đạo là tối/đen. Điều này khiến giao diện hiển thị không hề thay đổi nhưng phần màu sắc lại thay đổi mạnh mẽ, bên cạnh đó, nó cũng mang lại rất nhiều lợi ích bao gồm: lợi ích đối với sức khỏe con người (cải thiện giấc ngủ, mắt, tim, da mặt..), lợi ích với chính thiết bị đang sử dụng (cải thiện hiệu suất, khả năng tiêu thụ năng lượng…)
Trong bài viết này chúng ta sẽ cùng tìm hiểu cách để include darkmode cho website của chúng ta qua việc sử dụng CSS Variables.
Implement
Chúng ta sẽ add 3 options để user lựa chọn bao gồm: Dark, Light và Auto. Ngoài 2 mode Light và Dark đã khá thông dụng, ở đây ta có thêm mode Auto, ý nghĩa của mode này là nó sẽ dựa trên thiết lập theme của hệ thống đang sử dụng để quyết định xem mode hiện tại sẽ là Light hay là Dark.
Adding the HTML
Chúng ta sẽ thêm đoạn html để user lựa chọn giữa các mode:
1 2 3 4 5 6 | <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>select</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>theme<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>auto<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Auto<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>light<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Light<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>dark<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Dark<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>select</span><span class="token punctuation">></span></span> |
Adding the CSS
Chúng ta sẽ add thêm 1 chút CSS vào thẻ body
, là nơi ta chỉ định màu sắc cho mode Light
1 2 3 4 5 | <span class="token selector">body</span> <span class="token punctuation">{</span> <span class="token property">--background-color</span><span class="token punctuation">:</span> #ffffff<span class="token punctuation">;</span> <span class="token property">--text-color</span><span class="token punctuation">:</span> #000000<span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Để sử dụng CSS variables ở toàn bộ style sheet hoặc ở những chỗ cần thiết, ta có thể thêm như sau:
1 2 3 4 5 6 7 8 9 | <span class="token selector">.main-content</span> <span class="token punctuation">{</span> <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--background-color<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--text-color<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">button</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--text-color<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Tiếp theo ta sẽ implement mode Dark bằng cách thay thế các gía trị tương ứng vào các CSS variables vừa thêm ở bên trên:
1 2 3 4 5 6 7 8 9 10 | <span class="token selector">:root</span> <span class="token punctuation">{</span> <span class="token property">--dark-background-color</span><span class="token punctuation">:</span> #111111<span class="token punctuation">;</span> <span class="token property">--dark-text-color</span><span class="token punctuation">:</span> #eeeeee<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">body.theme-dark</span> <span class="token punctuation">{</span> <span class="token property">--background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--dark-background-color<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">--text-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>dark-text-color<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Đến bước này về cơ bản 2 mode Dark và Light đã hoạt động. Bây giờ chúng ta sẽ implement mode Auto:
1 2 3 4 5 6 7 | <span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">prefers-color-scheme</span><span class="token punctuation">:</span> dark<span class="token punctuation">)</span></span> <span class="token punctuation">{</span> <span class="token selector">body.theme-auto</span> <span class="token punctuation">{</span> <span class="token property">--background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--dark-background-color<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">--text-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--dark-text-color<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Ở đây chúng ta sử dụng Media Query để detect settings của hệ thống hiện tại có phù hợp với mode Dark hay không. Nếu điều kiện thỏa mãn, đoạn css bên trong @media
sẽ được thực thi, chi tiết về prefers-color-scheme
, các bạn có thể tham khảo thêm ở đây.
Chúng ta có thể check thử mode Auto này bằng cách chỉnh theme của OS sang darkmode hoặc view website qua điện thoại đang bật chế độ darkmode.
Adding the JavaScript
Phần implement CSS cho 3 mode đã xong, bước tiếp theo chúng ta sẽ thêm 1 chút javascript để list dropdown chọn giữa các mode hoạt động.
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">function</span> <span class="token function">applyTheme</span><span class="token punctuation">(</span><span class="token parameter">theme</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token string">"theme-auto"</span><span class="token punctuation">,</span> <span class="token string">"theme-light"</span><span class="token punctuation">,</span> <span class="token string">"theme-dark"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">theme-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>theme<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"DOMContentLoaded"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"#theme"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"change"</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">applyTheme</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Ở đây chúng ta xử lý việc bắt sự kiện change
của #theme
để chèn thêm class tương ứng vào thẻ body
A step further – remembering the theme
Để chức năng hoạt động hiệu quả hơn, chúng ta sẽ xử lý thêm việc browser sẽ nhớ mode đã setting trước đó cho trường hợp refresh, chuyển trang.. Để làm được điều này, chúng ta có thể sử dụng Local Storage.
Trước tiên chúng ta cần save lại giá trị theme được chọn:
1 2 | localStorage<span class="token punctuation">.</span><span class="token function">setItem</span><span class="token punctuation">(</span><span class="token string">"theme"</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span> |
Từ các lần gọi tiếp theo, chúng ta sẽ check giá trị theme
này để lựa chọn mode phù hợp:
1 2 | savedTheme <span class="token operator">=</span> localStorage<span class="token punctuation">.</span><span class="token function">getItem</span><span class="token punctuation">(</span><span class="token string">"theme"</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token string">"auto"</span><span class="token punctuation">;</span> |
Chúng ta sẽ loop qua từng option của #theme
để check xem nếu value có trùng với savedTheme
bên trên hay không, nếu có, ta sẽ set value đó là selected
:
1 2 3 4 | <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> optionElement <span class="token keyword">of</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">"#theme option"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> optionElement<span class="token punctuation">.</span>selected <span class="token operator">=</span> savedTheme <span class="token operator">===</span> optionElement<span class="token punctuation">.</span>value<span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Refactor lại logic DOMContentLoaded
chúng ta sẽ được như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"DOMContentLoaded"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> savedTheme <span class="token operator">=</span> localStorage<span class="token punctuation">.</span><span class="token function">getItem</span><span class="token punctuation">(</span><span class="token string">"theme"</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token string">"auto"</span><span class="token punctuation">;</span> <span class="token function">applyTheme</span><span class="token punctuation">(</span>savedTheme<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> optionElement <span class="token keyword">of</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">"#theme option"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> optionElement<span class="token punctuation">.</span>selected <span class="token operator">=</span> savedTheme <span class="token operator">===</span> optionElement<span class="token punctuation">.</span>value<span class="token punctuation">;</span> <span class="token punctuation">}</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"#theme"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"change"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> localStorage<span class="token punctuation">.</span><span class="token function">setItem</span><span class="token punctuation">(</span><span class="token string">"theme"</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">applyTheme</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Và thành quả:
Summary
Bài viết này nhằm giới thiệu và cùng tìm hiểu về cách để implement DarkMode cho website, bài viết còn thiếu sót, cảm ơn các bạn đã dành thời gian theo dõi.
Nguồn và tài liệu tham khảo: https://dev.to/dcodeyt/add-dark-mode-to-your-websites-with-css-5bh4