Dark Mode with a base CSS theme file, and a deltas add-on
Basic Setup With no user toggle support
- A fully themed Bootstrap CSS as a base file
- And a deltas add-on CSS with only the changes, filtered by stylesheet media filter
- Does not require jQuery
- Does not require fallback code
Replace the bootstrap stylesheet with the following code:
<!-- Bootstrap CSS -->
<!-- Inform modern browsers that this page supports both dark and light color schemes,
and the page author prefers light. -->
<meta name="color-scheme" content="light dark">
<!-- Load the primary CSS first ... -->
<link id="css-light" rel="stylesheet" href="bootstrap.css">
<!-- ... and then the alternate CSS first as a snap-on for dark color scheme preference -->
<link id="css-dark" rel="stylesheet" href="bootstrap-nightfall.css" media="(prefers-color-scheme: dark)">
This is all you need to enable dark mode with Bootstrap.
You also have the flexibility to give the user control with a toggle switch, but that requires some additional code.
Additional Setup Giving user control
The basic principle is honouring the browser preference (which we assume the user set with intent), detecting this state and setting a `dark
` data variable in the body.
We also update the toggle switch in the UI.
Once this switch has been clicked on, iether enable or disable the snap-on CSS based on the color scheme selection.
The following code will require jQuery:
<script>
$(document).ready(function(){
// Update the toggle button based on current color scheme
function updateDarkToggleButton() {
if (typeof $("body").attr("data-color-scheme") === 'undefined') {
$dark = (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches);
$("#css-toggle-btn").prop( "checked", $dark );
}
}
// Update on first load.
updateDarkToggleButton();
// and every time it changes
if (window.matchMedia) window.matchMedia("(prefers-color-scheme: dark)").addListener( updateDarkToggleButton );
// Color Scheme toggle botton
// function to toggle the css
function toggle_color_scheme_css($id, $mode) {
$dark = ($mode == 'dark') ? true : false;
$("#"+$id+"-dark").attr( "disabled", !$dark );
$("body").attr( "data-color-scheme", ($dark ? "dark" : "light" ) );
}
// function to initialise the css
function init_color_scheme_css($id, $mode) {
$dark = ($mode == 'dark') ? true : false;
toggle_color_scheme_css($id, $mode);
setTimeout(function(){ // let the browser catch up
$("#"+$id+"-dark").removeAttr("media");
}, 100);
}
// toggle button click code
$("#css-toggle-btn").bind("click", function() {
// get current mode
// don't use `.data("color-scheme")`, it doesn't refresh
$mode = $("body").attr("data-color-scheme");
// test if this is a first time click event, if so initialise the code
if (typeof $mode === 'undefined') {
// not defined yet - set pref. & ask the browser if alt. is active
$mode = 'light';
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) $mode = 'dark';
init_color_scheme_css("css", $mode);
}
// by here we have the current mode, so swap it
$mode = ($mode == 'dark') ? 'light' : 'dark';
toggle_color_scheme_css("css", $mode);
});
});
</script>
Remember that the above code does not include a persistence layer to remember a user toggled preference.
Read the README.md for more on this proof of concept.