Hi folks! Writing after a long gap again, going through a very busy schedule right now, I just want to share a quick and effective way to create a light and dark mode switching button for Ghost Blogs. It works with the default Source Theme. And you only need to do a code injection.
Inject this code at your site header and that's it
Go to your site's Admin area > Settings > Code Injection. And paste the code from below.
<!-- Floating Dark Mode Toggle Button with SVG Icons -->
<button class="theme-switch-button" aria-label="Toggle theme" onclick="toggleDarkMode()" style="position: fixed; top: 120px; right: 20px; z-index: 1000; background-color: transparent; border: none; cursor: pointer; padding: 10px;">
<div class="icon-moon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-moon" width="24" height="24">
<path d="M21 12.79A9 9 0 1111.21 3a7 7 0 1010.8 9.79z"></path>
</svg>
</div>
<div class="icon-sun" style="display: none;">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-sun" width="24" height="24">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</div>
</button>
<script>
// Function to toggle dark mode and change body background color
function toggleDarkMode() {
// Toggle the 'dark-mode' class on the body
const isDarkMode = document.body.classList.toggle('dark-mode');
// Change body background color based on mode
document.body.style.backgroundColor = isDarkMode ? '#191919' : '#ffffff'; // Dark or Light background
// Store the user's choice in local storage
localStorage.setItem('darkMode', isDarkMode);
// Update the icon visibility based on the current mode
updateIconVisibility(isDarkMode);
// Run contrast script to set text color based on the new background color
setTextColorBasedOnBackground();
}
// Function to update icon visibility based on the mode
function updateIconVisibility(isDarkMode) {
const moonIcon = document.querySelector('.icon-moon');
const sunIcon = document.querySelector('.icon-sun');
if (isDarkMode) {
moonIcon.style.display = 'none';
sunIcon.style.display = 'block';
} else {
moonIcon.style.display = 'block';
sunIcon.style.display = 'none';
}
}
// Function to dynamically set text color based on background color
function setTextColorBasedOnBackground() {
/* Get the current background color of the body element */
var accentColor = getComputedStyle(document.body).getPropertyValue('background-color');
// Convert RGB to hex format for YIQ calculation
var rgb = accentColor.match(/\d+/g);
var r = parseInt(rgb[0]);
var g = parseInt(rgb[1]);
var b = parseInt(rgb[2]);
var yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
// Determine if text color should be light or dark
var textColor = (yiq >= 128) ? 'dark' : 'light';
// Apply the determined text color class to the root element
document.documentElement.className = `has-${textColor}-text`;
}
// Function to check and apply dark mode preference from local storage
function loadDarkModePreference() {
const isDarkMode = localStorage.getItem('darkMode') === 'true';
if (isDarkMode) {
document.body.classList.add('dark-mode');
document.body.style.backgroundColor = '#191919'; // Set dark background
} else {
document.body.classList.remove('dark-mode');
document.body.style.backgroundColor = '#ffffff'; // Set light background
}
// Update icon visibility based on the loaded preference
updateIconVisibility(isDarkMode);
// Set the text color based on the loaded preference
setTextColorBasedOnBackground();
}
// Initial run to load dark mode preference
loadDarkModePreference();
// Function to adjust the button position on scroll
window.addEventListener('scroll', function() {
const button = document.querySelector('.theme-switch-button');
const initialPosition = 120; // Initial top position in pixels
const scrollOffset = window.scrollY; // Get the vertical scroll position
// Set the top position to initial position minus scroll offset, ensuring it doesn't go above 10px from the top
const newPosition = Math.max(initialPosition - scrollOffset, 10);
button.style.top = newPosition + 'px';
});
</script>
<style>
/* Define text color based on class */
.has-light-text {
color: #ffffff; /* Text color for light text */
}
.has-dark-text {
color: #000000; /* Text color for dark text */
}
/* Define background colors based on dark-mode class */
body.dark-mode {
--background-color: #191919; /* Dark background */
}
body:not(.dark-mode) {
--background-color: #ffffff; /* Light background */
}
/* Additional styling for the floating button */
.theme-switch-button {
position: fixed; /* Float button */
top: 120px; /* Position from top */
right: 20px; /* Position from right */
z-index: 1000; /* Make sure it appears above other elements */
background-color: transparent; /* Transparent background */
border: none; /* No border */
cursor: pointer; /* Pointer cursor on hover */
padding: 10px; /* Button padding */
}
.icon-moon, .icon-sun {
display: block; /* Display icons */
}
</style>
This code should work with the default Source theme, but please note that it doesn't work with any other themes. I am just using the function "Source" already use to dynamically colour text. And on this blog it self I am using a much more customised version on the this (which you can easily get from the source of my site).
There must be a downside:
And yes, there is one. To change your sites back ground color you need to update this part of the code and not at the design section of your site 🥲.
Yes here:
// Change body background color based on mode
document.body.style.backgroundColor = isDarkMode ? '#191919' : '#ffffff'; // Dark or Light background
And here:
if (isDarkMode) {
document.body.classList.add('dark-mode');
document.body.style.backgroundColor = '#191919'; // Set dark background
} else {
document.body.classList.remove('dark-mode');
document.body.style.backgroundColor = '#ffffff'; // Set light background
}
But it should not be a big problem unless you change your site background color too frequently.
Live example:
Conclusion
I hope this short post was helpful to you. And sorry for the infrequent posting, preparing heavily for the residency program (I wish to take up general surgery for my specialization and it is an Indian competitive exam). So wish me luck and hopefully we will meet again soon. And don't forget to comment down below whether this method worked properly or not.