I can use
@media (prefers-color-scheme: dark)
or
window.matchMedia('(prefers-color-scheme: dark)').matches
to detect whether it's a dark mode the OS.
However, is there any way that I can modify the status on my own with JavaScript? So that I can create a button to let the users switch between dark and light if they don't want to keep the OS's settings.
Perhaps the easiest way to support dark mode is to define all of your color settings for text, backgrounds, borders, shadows, etc. for your light theme, and then use a media query to override the colors, but as you noted, that doesn’t give your visitor the option to switch.
To give your visitors a choice, you can add a small, unobtrusive switch to your page (some sites, such as GitHub display a switch on their desktop version, but to switch on a mobile device, the user has to open the Settings function).
What I do is I save the user's preference in localStorage and I follow the stored preference the next time they come back (even if they’ve changed their system setting).
For displaying dark mode, I add a dark-mode class to the documentElement (the html tag). In my CSS, I have a second set of CSS rule-sets:
Another option for switching the colors is to apply a data-color-mode="dark" attribute on the tag and using CSS variables:
The CSS variables won’t work with Internet Explorer, so it will revert to IE’s standard colors.
As I still need to support IE9 and up, I don’t use the CSS variable option and, because I use an intersectionObserver based lazy-load, I don’t give IE users the option to switch the theme — they automatically get the light theme.
To make it work, I have the following code in my head section:
IE9 doesn’t support classList, but I optionally load a polyfill if the visitor is using IE9.
To set up the switch function, I have the following code at the bottom of my page:
Toggling the switch causes the page to reload the images, loading dark instead of light or vise versa.