How to Make an Animated Day and Night Toggle Switch

How to Make an Animated Day and Night Toggle Switch

With vanilla Javascript and CSS
Ferenc Almasi • šŸ”„ 2021 November 11 • šŸ“– 8 min read

Providing an option for your users to toggle between a dark and light theme can be a great way to let them:

  • Reduce the brightness of your site at night
  • Save battery power when low
  • Or just provide a different version of your site for their preference

We will look at how you can create an animated toggle button with only CSS. We will also be looking at how you can use CSS variables to define different color schemes. And by the end of this tutorial, you will be able to build a light switcher, like the one below:

switching the lights on an off with CSS
Looking to improve your skills? Check out our interactive course to master JavaScript from start to finish.
Master JavaScript

Setting Things Up

Create anĀ index.htmlĀ file at the root of your project and fill it with the following:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Day & Night Toggle Switch</title>

        <link rel="stylesheet" href="colors.css" />
        <link rel="stylesheet" href="styles.css" />
    </head>
    <body>
        <span class="toggle"></span>

        <div class="wrapper">
            <h1>Day & Night</h1>
            <h2>Toggle Switch</h2>
            <p>Created with CSS</p>
            <span>Using <b>CSS</b> variables</span>
        </div>

        <script src="toggle.js"></script>
    </body>
</html>
index.html
Copied to clipboard!

We’re going to have three different resources:

  • colors.cssĀ will hold all the color definitions
  • styles.cssĀ will hold the styles for theĀ .toggleĀ as well as theĀ .wrapper
  • toggle.jsĀ will hold a click event listener for toggling classes

Let’s go over each and see what we need to add for them. At first, we want to create the toggle.


Creating The Toggle

Open up yourĀ styles.cssĀ and define the following styles for theĀ .toggle:

.toggle {
    position: absolute;
    cursor: pointer;
    top: 20px;
    right: 25px;
    font-size: 150%;
}

.toggle:before {
    content: 'ā˜€ļø';
}

.toggle.active:before {
    content: 'šŸŒ’';
}
styles.css
Copied to clipboard!

I have to mention two important things here. First, you should setĀ cursorĀ toĀ pointerĀ to provide visual feedback to the user that the element can be interacted with. Secondly, we want to change the icon — which is in the content of theĀ beforeĀ pseudo-element — based on anĀ .activeĀ class.

toggling the active class in DevTools
Adding the active class in DevTools toggles the icon

Of course, we don’t want to toggle the class through DevTools, so let’s add the event listener in JavaScript.

Adding the Event Listener

For this to work, we need the following function attached to theĀ .toggleĀ element.

document.querySelector('.toggle').addEventListener('click', function() {
    this.classList.toggle('active');
});
toggle.js
Copied to clipboard!

At this point, we are able to toggle the icon on and off. To spice things up, let’s also add some animation.

toggling the class through JavaScript
Clicking the icon toggles the class

Adding the Scaling Animation

The animation will work in the following way: We scale the icon down to 0. When it hits 0, the icon is essentially invisible. This is when we need to toggle theĀ .activeĀ class to change the icon. Then we scale the icon back to its original size.

How the scaling animation will work

To achieve this, add the following to yourĀ style.cssĀ file:

.toggle.animate {
    animation: animate .3s cubic-bezier(0.4, 0.0, 0.2, 1);
}

@keyframes animate {
    0%   { transform: scale(1); }
    50%  { transform: scale(0); }
    100% { transform: scale(1); }
}
style.css
Copied to clipboard!

We will animate the icon in 300ms to make the animation fast. To handle this through JavaScript, we will also need to modify our event listener a bit.

 document.querySelector('.toggle').addEventListener('click', function() {
+    this.classList.add('animate');
    
+    setTimeout(() => {
        this.classList.toggle('active');
+    }, 150);
    
+    setTimeout(() => this.classList.remove('animate'), 300);
});
toggle.diff
Copied to clipboard!

First, we need to add the animate class to start the animation. At the half of the animation — which is set to 300ms inĀ styles.css, so we need to use 150 here — we toggle theĀ .activeĀ class. At the end of the animation, we can remove theĀ .animateĀ class.

animating the icon with transform: scale
Animating the icon with transform: scale
Looking to improve your skills? Check out our interactive course to master JavaScript from start to finish.
Master JavaScript

Adding The Ripple Effect

To make the background transition feel like a wave, we can use a CSS trick instead of changing theĀ background-colorĀ property. We will animate theĀ box-shadowĀ instead. For this to work, we need a new element. Add the following line to yourĀ index.htmlĀ file:

<!DOCTYPE html>
<html lang="en">
    <head>
        ...
    </head>
    <body>
        <span class="toggle"></span>
        <span class="wave"></span>

        ...
    </body>
</html>
index.html
Copied to clipboard!

Since we are already doing some animation on theĀ .toggleĀ element, we don’t want to animate itsĀ box-shadow, otherwise, we would get weird effects. That is why we need to use a separate element. Let’s define the styles associated with the it.

.wave {
    position: absolute;
    top: 35px;
    right: 40px;
    border-radius: 100%;
    width: 2px;
    height: 2px;
    display: block;
    z-index: -1;
    box-shadow: 0 0 0 0 #212121;
    transition: box-shadow .3s cubic-bezier(0.4, 0.0, 0.2, 1);
}

.wave.active {
    background: #212121;
    box-shadow: 0 0 0 9999px #212121;
}
styles.css
Copied to clipboard!

Some important things I would like to point out:

  • TheĀ .waveĀ needs to be positioned exactly in the middle of the icon, so it starts growing from its inside.
  • ItsĀ border-radiusĀ needs to be set to 100% to be circular.
  • Why theĀ 2pxĀ for width and height? This is the smallest size on whichĀ border-radiusĀ works.
  • You’ll also need to setĀ z-indexĀ to -1 to make sure it doesn’t cover other elements on the page.
  • I set theĀ background-colorĀ purposefully to black on theĀ .activeĀ state to prevent a white dot showing in place of the icon, when it’s invisible.
changing the box shadow on the wave element

If we start changing the size of theĀ box-shadow, we can see that the background slowly turns into darkness. Let’s also update the event listener in JavaScript:

document.querySelector('.toggle').addEventListener('click', function() {
    this.classList.add('animate');
   
    setTimeout(() => {
        this.classList.toggle('active');
        document.querySelector('.wave').classList.toggle('active');
    }, 150);
   
    setTimeout(() => this.classList.remove('animate'), 300);
});
toggle.js You can also toggle the class outside the setTimeout if you want immediate effect
Copied to clipboard!
toggling the toggle with wave effect applied
I’ve changed the transition’s speed to 1s to prevent the GIF making the animation look laggy

Adding Color Definitions

All that’s left to do is to add the color definitions so we have different styles for different themes. Open up yourĀ colors.cssĀ file and fill it with the following content:

html {
    --background: #212121;
    --box-shadow: #000;
    --text: #FFF;
    --text-faded: #CCC;
    --badge-background: #162F48;
    --badge-color: #0B81D0;
}

.theme-dark {
    --background: #FFF;
    --box-shadow: #CCC;
    --text: #212121;
    --text-faded: #333;
    --badge-background: #FFDA44;
    --badge-color: #d35400;
}
colors.css
Copied to clipboard!

As you can see, we don’t have anything, besides the colors. All we are doing here is rewriting the CSS variables for different themes. Again, we want to toggle a class, but this time, on the HTML element itself.

document.querySelector('.toggle').addEventListener('click', function() {
    this.classList.add('animate');
    
    setTimeout(() => {
        this.classList.toggle('active');
        document.querySelector('.wave').classList.toggle('active');
        document.documentElement.classList.toggle('theme-dark');
    }, 150);
    
    setTimeout(() => this.classList.remove('animate'), 300);
});
toggle.js
Copied to clipboard!

This is the last thing to add in theĀ .toggleĀ event listener. So how would you use these variables inside CSS? Instead of hard-coding colors, you can use theĀ varĀ function to retrieve the values from the defined colors.

.wrapper {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    padding: 20px;
    background: var(--background);
    color: var(--text);
    border-radius: 5px;
    box-shadow: 0 3px 0 0 var(--box-shadow);
    transition: all .3s cubic-bezier(0.4, 0.0, 0.2, 1);
}
styles.css
Copied to clipboard!

Make sure you add aĀ transitionĀ property to smoothly animate the colors. All that’s left to do is to test everything out.

switching the lights on an off with CSS
Looking to improve your skills? Check out our interactive course to master JavaScript from start to finish.
Master JavaScript

Summary

In roughly 10 lines of JavaScript code, you are able to create a day-night toggle switch to help your users in various ways. It’s easy to implement and highly customizable. With the help of CSS variables, you can also create multiple themes by simply adding another class with another set of color schemes.

If you would like to experiment with the finished project, you canĀ clone it from GitHub. Thank you for taking the time to read this article. Happy coding!

Simple Ways to Fake Masonry in CSS
Did you find this page helpful?
šŸ“š More Webtips
Frontend Course Dashboard
Master the Art of Frontend
  • check Unlimited access to hundred of tutorials
  • check Access to exclusive interactive lessons
  • check Remove ads to learn without distractions
Become a Pro

Recommended