DEV Community

Cover image for Dark mode toggle animation using CSS !
Murtuzaali Surti
Murtuzaali Surti

Posted on • Updated on

Dark mode toggle animation using CSS !

This tutorial will mainly focus on how to use transitions in CSS and make a toggle button for light as well as dark mode using little JavaScript. Let's dive into the world of transitions!

HTML

HTML Markup is pretty simple to understand. All you have to do is to make a container for the icons that we are going to use from fontawesome and nest the respective divs containing the icons inside the container.



<div class="container">
   <div class="sun sun-logo">
      <i class="fas fa-sun"></i>
   </div>
   <div class="moon moon-logo">
      <i class="fas fa-moon"></i>
   </div>
</div>


Enter fullscreen mode Exit fullscreen mode

CSS



.container{
    position: relative;
}

.sun, .moon{
    font-size: 10rem;
    width: fit-content;
    height: fit-content;
}

.moon{
    position: absolute;
    inset: 0;
}


Enter fullscreen mode Exit fullscreen mode

Set the container position to be relative and the moon container position to be absolute because we will position the moon icon in the same position as that of the sun icon.

Here's the interesting part. Instead of using top: 0; bottom: 0; left: 0; and right: 0; you can use inset: 0; to get the same result. It works!

Also, set the height and width of the sun and the moon container to fit-content. What this will do is, it will set the height and width of the container to match the height and width of the content inside it.

And, in order to change the size of the fontawesome icon, just change the font-size of the icon.



.moon-logo{
    opacity: 0;
    transform: translateY(20%) rotateZ(50deg);
}


Enter fullscreen mode Exit fullscreen mode

Next, we will set up the initial position of the moon icon and its initial opacity when the webpage is rendered for the first time. Here, as the opacity of the moon icon is zero, only the sun icon will be visible to us.

The translateY(20%) declaration will offset the moon icon down along the Y-axis by 20% of the height of it's parent element.

Similarly, the rotateZ(50deg) declaration will rotate the moon icon along the Z-axis by 50 degrees.



.sun-logo{
    opacity: 1;
    transform: translateY(0) rotateZ(0deg);
}


Enter fullscreen mode Exit fullscreen mode

In the same way, we will set the initial properties for the sun icon.



.animate-sun{
    opacity: 0;
    transform: translateY(20%) rotateZ(100deg);
    color: aliceblue;
}


Enter fullscreen mode Exit fullscreen mode

Now, we will set the final properties of the sun icon to which it will transition into.



.animate-moon{
    opacity: 1;
    transform: translateY(0%) rotateZ(0deg);
    color: aliceblue;
}


Enter fullscreen mode Exit fullscreen mode

Also, we will set the final properties of the moon icon to which it will transition into. One thing to note here is the default color of the icons is black, so if you want to change the color of the icon, then define its color property.

But wait, we haven't used the transition property yet, so how will it transition from one state to another? Yeah, that's the only thing left to do in CSS part.



.moon-logo{
    opacity: 0;
    transform: translateY(20%) rotateZ(50deg);
    transition: all 1s ease-out;
}
.sun-logo{
    opacity: 1;
    transform: translateY(0) rotateZ(0deg);
    transition: all 1s ease-out;
}


Enter fullscreen mode Exit fullscreen mode


body{
    transition: background-color 1s;
}

.dark{
    background-color: black;
}


Enter fullscreen mode Exit fullscreen mode

We will use the above class to change the background-color of the body when the transition of the icons will happen.

That's it. Your CSS part is ready.

Now, let's move on to the JavaScript part. We will use JavaScript to toggle the classes on click event.

JavaScript



document.querySelector(".container").addEventListener("click", () => {
    document.querySelector(".sun-logo").classList.toggle("animate-sun");
    document.querySelector(".moon-logo").classList.toggle("animate-moon");
    document.querySelector("body").classList.toggle("dark");
})


Enter fullscreen mode Exit fullscreen mode

Here, we have added an eventListener to the container element so that when we click on the container, it will toggle the CSS classes for respective elements.
Which means that, if the CSS class is not present in the classList of an element, toggle function will add the CSS class to the classList of the respective element.

And, if the CSS class is already present in the classList of the element, it will remove it.

The classList is actually a DOMTokenList but we will not go into the specifics of it.

This is it. Here's the final output.

Final Output GIF

Top comments (36)

Collapse
 
syntaxhacker profile image
syntaxhacker

i suggest you to embed the example using codepen

Collapse
 
murtuzaalisurti profile image
Murtuzaali Surti

It's now embedded!

Collapse
 
murtuzaalisurti profile image
Murtuzaali Surti

Okay, I will embed it!

Collapse
 
robole profile image
Rob OLeary • Edited

Hi Murtuza,

I have one suggestion. For accessibility, it would be better if you use button instead of div for the container. A button gets focus for keyboard users and is announced by screen readers as something actionable. When there is no text inside, you can add an aria-label attribute.

Something like this:

<button class="container" aria-label="Dark mode toggle">
   <!-- existing code -->
</button.
Enter fullscreen mode Exit fullscreen mode
Collapse
 
murtuzaalisurti profile image
Murtuzaali Surti

Thanks for mentioning that! I will take care of that.

Collapse
 
violet profile image
Elena

A more efficient way to get the body is to use document.body instead of document.querySelector("body"). Same thing applies to classes. It's faster for the browser to fetch classes with document.getElementsByClassName('container')[0] instead of using document.querySelector(".container").

To make the js use less code I would add the animation css to the body.dark .sun-logo and body.dark .moon-logo instead of toggling the classes on each button.

Collapse
 
murtuzaalisurti profile image
Murtuzaali Surti

I intentionally did the toggling because I wanted to create separate classes because of the transform property. The transform property is explicitly stated for the initial position.

Collapse
 
originalix profile image
Leon

I suggest you use highlight for your code. 😃

Collapse
 
murtuzaalisurti profile image
Murtuzaali Surti

Oh, I didn't get it. How would you do that?

Collapse
 
originalix profile image
Leon • Edited

You can add the program language tag when you use markdown code syntax.
Like this:
https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b5zu0cqog7bke0jpml9z.png

Thread Thread
 
murtuzaalisurti profile image
Murtuzaali Surti

That's amazing! Thanks for telling me. I wasn't aware of this. 🙌

Thread Thread
 
originalix profile image
Leon

Lol, Now this article looks more pretty.👍

Thread Thread
 
murtuzaalisurti profile image
Murtuzaali Surti

Yup :)

Collapse
 
ttebify profile image
ttebify

Weldone! I see you have a color property of value aliceblue in both icons. But I didn't notice any color change during the transition. Could it be because you placed it after the css opacity property, so it becomes fully transparent before any significant color change?

Collapse
 
ttebify profile image
ttebify

I just observed now that you don't have the color property set in the CodePen version.

Collapse
 
murtuzaalisurti profile image
Murtuzaali Surti

Yeah, because I have used SVG icons there and you must use fill property instead of color property in order to change the color of the SVG element.

Collapse
 
murtuzaalisurti profile image
Murtuzaali Surti

Color change is visible. If you want to see it in slow motion, just increase the duration of the transition!

Collapse
 
mendozalz profile image
Lenin Mendoza

Lo he solucionado, el script debe cargarse al final del body

Collapse
 
merthod profile image
Merthod

O usa defer

Collapse
 
murtuzaalisurti profile image
Murtuzaali Surti • Edited

Great! You have to link your CSS and JavaScript file in your HTML page..

Collapse
 
genakalinovskiy profile image
Gena Kainovskiy

I thought it would be only with css , but you had used javascript :)

Collapse
 
murtuzaalisurti profile image
Murtuzaali Surti

It's only for toggling the classes on 'click' event.

Collapse
 
genakalinovskiy profile image
Gena Kainovskiy • Edited

I think it was possible to do with checkbox ) if we speak about css only .

Thread Thread
 
murtuzaalisurti profile image
Murtuzaali Surti

Yeah, that is a decent trick.. You can visually hide the checkbox and add another element on it.. but it can have some accessibility issues..

Thread Thread
 
genakalinovskiy profile image
Gena Kainovskiy

Thank you for article)

Thread Thread
 
murtuzaalisurti profile image
Murtuzaali Surti

I'm glad

Collapse
 
mendozalz profile image
Lenin Mendoza

esta muy bueno, pero lo he intentado y nada que me sale y he sido muy cuidadoso al punto de hacer tal cual como esta aquí sin cambiar nada desde mi entorno local.

Collapse
 
ascodeyt profile image
Ascodeyt

your writing code have some mistek please solve it its not changing moon icon

Collapse
 
murtuzaalisurti profile image
Murtuzaali Surti • Edited

Make sure to link your CSS and JavaScript file with your HTML..
If you are still facing issues, then refer the CodePen of this tutorial.

Collapse
 
devmatias profile image
Matias Maximiliano Robledo

Great!

Collapse
 
murtuzaalisurti profile image
Murtuzaali Surti

Thanks 😊