DEV Community

Cover image for Dark/Light theme switcher with HTML, CSS & Javascript Only
Kelven Rubalaine
Kelven Rubalaine

Posted on • Updated on

Dark/Light theme switcher with HTML, CSS & Javascript Only

There are different ways to implement dark mode on websites, from the simplest to the most complex, and the approach I show in this short tutorial I consider as the simplest and painless possible, for this we will implement using only HTML, CSS and Javascript.

Two key concepts will be used for implementing dark mode, CSS Variables for colors, and localStorage to store the user's current theme.

CSS Variables

CSS variables work like variables from any other language, where we assign values to it and we can modify it later, for implementation of dark mode we will assign the values of our colors to CSS variables, with that we can modify them later depending on the context.

/*creating a css variable */
--bg-grey-light: #f5f5f5;

/*using the css variable */
background-color: var(--bg-grey-light);
Enter fullscreen mode Exit fullscreen mode

A special feature of CSS variables that makes it a good alternative to implementing dark mode is that all elements that are declared inside the parent element will
inherits them, so we'll define our variables directly in the body so that all elements within it can inherit them.

localStorage API

For a better user experience, we will use localStorage which will store the user's current theme, that way when the user comes back to the website, their favorite theme will be applied automatically.

// storing the theme on the user's machine
localStorage.setItem('theme', 'dark');

//accessed the user's machine theme
localStorage.getItem('theme');
// dark
Enter fullscreen mode Exit fullscreen mode

Document Structure

Being a very small project, our document will consist of two buttons and two blocks of text, the buttons will have the function of changing the theme and updating the page.

index.html

  <body>
     <div class="container">
       <h1 class="heading">
         How to make dark mode with HTML, CSS and Javascript only
       </h1>
       <div class="buttons">
         //button to switch dark/light states
         <button id="toggle" class="button">toggle</button>
         //button to refresh the page
         <button id="refresh" class="button">refresh</button>
       </div>
       <div class="text-wrapper">
         <p class="paragraph">
           The United States shall be President of the....
         </p>
       </div>
       <div class="text-wrapper">
         <p class="paragraph">
           Why, there's hardly enough of me left...
         </p>
       </div>
     </div>
     <script src="script.js"></script>
   </body>
Enter fullscreen mode Exit fullscreen mode

Defining the colors

Since we are dealing with two different contexts, for each color in the light theme there must be a variant for the dark theme, and the colors have to be defined according to your responsibilities, thus having colors for text, background colors…

Definition of variables

/* Definition of colors */
body {
   /* text colors */
   --text-white: #ffffff;
   --text-dark: #142136;

   /* background colors */
   --bg-grey-light: #f5f5f5;
   --bg-white: #ffffff;
   --bg-blue-dark: #142136;
   --bg-indigo: #6366f1;

   /*
...
*/
}
Enter fullscreen mode Exit fullscreen mode

After defining the variables, we will create a class named .dark, which will contain the definition of the same variables, but with the value of the colors changed to the dark theme, so when we want to change the context to the dark theme, we just add the .dark class to the body via javascript so the variables previously defined will be overwritten by the ones defined in the .dark class.

Variables for the dark theme

.dark {
   --text-white: #e6e6e6;
   --text-dark: #ffffff;

   --bg-grey-light: #142136;
   --bg-white: #22395d;
   --bg-blue-dark: #142136;
   --bg-indigo: #7577e1;
}
}
Enter fullscreen mode Exit fullscreen mode

note that the --text-dark variable which had its value: #142136, was changed to #ffffff in the context of the dark theme, keeping that in mind, you just need to repeat the same process for all other colors of your code.

How did the final .css file look like:

style.css

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
/* Definition of colors */
body {
  /* text colors */
  --text-white: #ffffff;
  --text-dark: #142136;

  /* background colors */
  --bg-grey-light: #f5f5f5;
  --bg-white: #ffffff;
  --bg-blue-dark: #142136;
  --bg-indigo: #6366f1;

  font-family: "Inter", sans-serif;
  line-height: 1.7;
  background-color: var(--bg-grey-light);
}
.dark {
  --text-white: #e6e6e6;
  --text-dark: #ffffff;
  --bg-grey-light: #142136;
  --bg-white: #22395d;
  --bg-blue-dark: #142136;
  --bg-indigo: #7577e1;
}
.container {
  max-width: 600px;
  margin: 40px auto;
  display: flex;
  padding: 20px;
  flex-direction: column;
}
.text-wrapper {
  width: 100%;
  padding: 20px;
  background-color: var(--bg-white);
  margin-bottom: 40px;
  border-radius: 10px;
}
.paragraph {
  font-size: 16px;
  color: var(--text-dark);
}
.heading {
  font-size: 40px;
  letter-spacing: 1px;
  font-weight: 900;
  margin-bottom: 40px;
  color: var(--text-dark);
}
.buttons {
  width: 100%;
  display: flex;
  justify-content: space-between;
  margin-bottom: 40px;
}
.button {
  width: 200px;
  padding: 5px;
  height: 40px;
  border: none;
  border-radius: 10px;
  font-family: inherit;
  cursor: pointer;
  background-color: var(--bg-indigo);
  color: var(--text-white);
  font-size: 16px;
  font-weight: 400;
  text-transform: capitalize;
}
Enter fullscreen mode Exit fullscreen mode

As you can see in the code, no color was used directly, instead we used the previously defined variables.

Changing Theme

To switch the theme, we will use javascript, and the script will first check in localStorage if the previously stored theme is dark and apply it to body as soon as it loads.
We add an eventListener to the toggle button so when it is clicked it will remove or add the .dark class and also change the theme stored in localstorage depending on context.

script.js

const toggle = document.getElementById("toggle");
const refresh = document.getElementById("refresh");
const theme = window.localStorage.getItem("theme");

/* checks if the theme stored in localStorage is dark
if yes apply the dark theme to the body */
if (theme === "dark") document.body.classList.add("dark");

// event listener stops when the change theme button is clicked
toggle.addEventListener("click", () => {
   document.body.classList.toggle("dark");
   if (theme === "dark") {
     window.localStorage.setItem("theme", "light");
   } else window.localStorage.setItem("theme", "dark");
});

refresh.addEventListener("click", () => {
   window.location.reload();
});
Enter fullscreen mode Exit fullscreen mode

Demo: dark-mode.kelven.dev
Source code: Github Repo

Thank you so much for reading this far, I hope my text somehow helped you.
This is my second article/blog post, so feel free to give your opinion about it, which helps me improve.
Take a look at my Portfolio I have some interesting projects there.

Discussion (4)

Collapse
darkwiiplayer profile image
DarkWiiPlayer

"dark mode with every technology on the web only"

NGL that title is a bit funny xD

I'd recommend something with a bit more of a hook to get people to read the article; Dark/Light theme switchers are a very common thing and don't really work well to grab attention.

Another nitpick: Some people (including me) block cookies and other storage by default, so it might be worth adding a check for that so the switcher still works, albeit without persistence.

Collapse
jmau111 profile image
J.

Nicely done. I see only one caveat with this method: Flash of inAccurate coloR (FART).
That's because the js is placed at the bottom of the page. Besides, it does not take into account user system preferences.

As far as I know, you're kinda forced to put a render-blocking js at the top of the head section to prevent the FART effect, and you can use if (window.matchMedia('(prefers-color-scheme: dark)').matches) to detect user preferences in js.

Collapse
eugeneve profile image
Eugene Veprytskyi

Android application flatter only 😂

Collapse
lakinduk profile image
Lakindu Kariyawasam

A clever approach to dark theme theme.
Nice article article. 👍