3

I'm working on a little animation for toggling my website between dark- and light mode. It's a pretty complicated animation, so I'm guessing the solution will be complicated as well.

I basically toggle between classes, but this prevents me from being able to reverse the animation when toggling the button. Been looking for simple solutions around the web, but didn't find any that explains how to reverse the animation with multiple CSS keyframes.

Here's the CSS part of the code which is basically repeated 8 times:

.line {
width: 1rem;
height: 2rem;
background-color: black;
position: absolute;
display: block;
transform: translateY(5rem);
border-radius: 0.5em;
}
.is-dark {
animation: is-dark 2s forwards;
}
@keyframes is-dark {
    0% {
        height: 2rem;
        width: 1rem;
        border-radius: 0.5em;
        transform: translateX(0) translateY(5rem);
    }
    33.33% {
        height: 1rem;
        width: 1rem;
        border-radius: 50%;
        transform: translateX(0) translateY(5rem);
    }
    66.66% {
        height: 3rem;
        width: 3rem;
        border-radius: 50%;
        transform: translateX(0) translateY(0);
    }
    100% {
        height: 3rem;
        width: 3rem;
        border-radius: 50%;
        transform: translateX(1rem) translateY(-1rem);
    }
}

JS

let line = document.querySelector(".line");

let btn = document.querySelector(".btn");

btn.addEventListener("click", toggleDarkMode);

function toggleDarkMode() {
  line.classList.toggle("is-dark");
}

Here's the complete version of this button: https://jsfiddle.net/a6euokxy/4/

Thanks in advance, Luk Ramon

1 Answer 1

1

I have some the solution for you issue. I improved js file, did add into classes with animation alternate infinite paused; properties. In html added classes with animation.

working example with LocalStorage

let theme = 'light';
// Get all container elements
const lines = document.querySelector('.container').querySelectorAll('div');

let btn = document.querySelector('.btn');

btn.addEventListener('click', toggleDarkMode);

function toggleDarkMode() {
  if (theme === 'light') {
    lines.forEach(line => {
      // Remove unnecessary DOM elements
      if (!line.hasAttribute('class')) return;
      // Set pause after play 2s animation
      setTimeout(() => {
        line.removeAttribute('style');
      }, 2000);
      // Start play
      line.setAttribute('style', 'animation-play-state: running');
    });
    theme = 'dark';
    return;
  }

  if (theme === 'dark') {
    lines.forEach(line => {
      if (!line.hasAttribute('class')) return;

      setTimeout(() => {
        line.removeAttribute('style');
      }, 2000);

      line.setAttribute('style', 'animation-play-state: running');
    });
    theme = 'light';
    return;
  }
}
* {
  padding: 0;
  margin: 0;
}

.button {
  display: flex;
  justify-content: center;
  margin-top: 3rem;
}

.button .btn {
  background: none;
  border: 0.2rem solid black;
  font-size: 1rem;
  padding: 1rem;
  border-radius: 2rem;
  font-weight: bold;
}

.container {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

#circle {
  width: 4rem;
  height: 4rem;
  border: 1rem solid black;
  border-radius: 50%;
  position: absolute;
}

#lines {
  display: flex;
  justify-content: center;
  align-items: center;
}

#lines1 {
  transform: rotate(45deg);
  transform-origin: center;
  position: absolute;
  display: flex;
  justify-content: center;
  align-items: center;
}

.line,
.line1,
.line2,
.line3,
.line4,
.line5,
.line6,
.line7 {
  width: 1rem;
  height: 2rem;
  background-color: black;
  position: absolute;
  display: block;
  border-radius: 0.5em;
}

.line {
  transform: translateY(5rem);
}

.is-dark {
  animation: is-dark 2s alternate infinite paused;
}

@keyframes is-dark {
  0% {
    height: 2rem;
    width: 1rem;
    border-radius: 0.5em;
    transform: translateX(0) translateY(5rem);
  }
  33.33% {
    height: 1rem;
    width: 1rem;
    border-radius: 50%;
    transform: translateX(0) translateY(5rem);
  }
  66.66% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateX(0) translateY(0);
  }
  100% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateX(1rem) translateY(-1rem);
  }
}

.line1 {
  transform: translateY(-5rem);
}

.is-dark1 {
  animation: is-dark1 2s alternate infinite paused;
}

@keyframes is-dark1 {
  0% {
    height: 2rem;
    width: 1rem;
    border-radius: 0.5em;
    transform: translateY(-5rem);
    opacity: 100%;
  }
  33.33% {
    height: 1rem;
    width: 1rem;
    border-radius: 50%;
    transform: translateY(-5rem);
    opacity: 100%;
  }
  66.66% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateY(0);
    opacity: 100%;
  }
  66.67% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateY(0);
    opacity: 0;
  }
  100% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateY(0);
    opacity: 0;
  }
}

.line2 {
  transform: translateX(5rem) rotate(90deg);
}

.is-dark2 {
  animation: is-dark2 2s alternate infinite paused;
}

@keyframes is-dark2 {
  0% {
    height: 2rem;
    width: 1rem;
    border-radius: 0.5em;
    transform: translateX(5rem) rotate(90deg);
    opacity: 100%;
  }
  33.33% {
    height: 1rem;
    width: 1rem;
    border-radius: 50%;
    transform: translateX(5rem) rotate(90deg);
    opacity: 100%;
  }
  66.66% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateX(0) rotate(90deg);
    opacity: 100%;
  }
  66.67% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateX(0) rotate(90deg);
    opacity: 0;
  }
  100% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateX(0) rotate(90deg);
    opacity: 0;
  }
}

.line3 {
  transform: translateX(-5rem) rotate(90deg);
}

.is-dark3 {
  animation: is-dark3 2s alternate infinite paused;
}

@keyframes is-dark3 {
  0% {
    height: 2rem;
    width: 1rem;
    border-radius: 0.5em;
    transform: translateX(-5rem) rotate(90deg);
    opacity: 100%;
  }
  33.33% {
    height: 1rem;
    width: 1rem;
    border-radius: 50%;
    transform: translateX(-5rem) rotate(90deg);
    opacity: 100%;
  }
  66.66% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateX(0) rotate(90deg);
    opacity: 100%;
  }
  66.67% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateX(0) rotate(90deg);
    opacity: 0;
  }
  100% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateX(0) rotate(90deg);
    opacity: 0;
  }
}

.line4 {
  transform: translateY(5rem);
}

.is-dark4 {
  animation: is-dark4 2s alternate infinite paused;
}

@keyframes is-dark4 {
  0% {
    height: 2rem;
    width: 1rem;
    border-radius: 0.5em;
    transform: translateX(0) translateY(5rem);
    opacity: 100%;
  }
  33.33% {
    height: 1rem;
    width: 1rem;
    border-radius: 50%;
    transform: translateX(0) translateY(5rem);
    opacity: 100%;
  }
  66.66% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateX(0) translateY(0);
    opacity: 100%;
  }
  66.67% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateX(1rem) translateY(1rem);
    opacity: 0;
  }
  100% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateX(1rem) translateY(1rem);
    opacity: 0;
  }
}

.line5 {
  transform: translateY(-5rem);
}

.is-dark5 {
  animation: is-dark5 2s alternate infinite paused;
}

@keyframes is-dark5 {
  0% {
    height: 2rem;
    width: 1rem;
    border-radius: 0.5em;
    transform: translateY(-5rem);
    opacity: 100%;
  }
  33.33% {
    height: 1rem;
    width: 1rem;
    border-radius: 50%;
    transform: translateY(-5rem);
    opacity: 100%;
  }
  66.66% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateY(0);
    opacity: 100%;
  }
  66.67% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateY(0);
    opacity: 0;
  }
  100% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateY(0);
    opacity: 0;
  }
}

.line6 {
  transform: translateX(5rem) rotate(90deg);
}

.is-dark6 {
  animation: is-dark6 2s alternate infinite paused;
}

@keyframes is-dark6 {
  0% {
    height: 2rem;
    width: 1rem;
    border-radius: 0.5em;
    transform: translateX(5rem) rotate(90deg);
    opacity: 100%;
  }
  33.33% {
    height: 1rem;
    width: 1rem;
    border-radius: 50%;
    transform: translateX(5rem) rotate(90deg);
    opacity: 100%;
  }
  66.66% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateX(0) rotate(90deg);
    opacity: 100%;
  }
  66.67% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateX(0) rotate(90deg);
    opacity: 0;
  }
  100% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateX(0) rotate(90deg);
    opacity: 0;
  }
}

.line7 {
  transform: translateX(-5rem) rotate(90deg);
}

.is-dark7 {
  animation: is-dark7 2s alternate infinite paused;
}

@keyframes is-dark7 {
  0% {
    height: 2rem;
    width: 1rem;
    border-radius: 0.5em;
    transform: translateX(-5rem) rotate(90deg);
    opacity: 100%;
  }
  33.33% {
    height: 1rem;
    width: 1rem;
    border-radius: 50%;
    transform: translateX(-5rem) rotate(90deg);
    opacity: 100%;
  }
  66.66% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateX(0) rotate(90deg);
    opacity: 100%;
  }
  66.67% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateX(0) rotate(90deg);
    opacity: 0;
  }
  100% {
    height: 3rem;
    width: 3rem;
    border-radius: 50%;
    transform: translateX(0) rotate(90deg);
    opacity: 0;
  }
}
<div class="button">
  <button class="btn">Dark Mode</button>
</div>
<div class="container">
  <div id="circle"></div>
  <div id="lines">
    <div class="line is-dark"></div>
    <div class="line1 is-dark1"></div>
    <div class="line2 is-dark2"></div>
    <div class="line3 is-dark3"></div>
  </div>
  <div id="lines1">
    <div class="line4 is-dark4"></div>
    <div class="line5 is-dark5"></div>
    <div class="line6 is-dark6"></div>
    <div class="line7 is-dark7"></div>
  </div>
</div>

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks @ЖнецЪ for your time, although there's a little issue. When spamming the button, an action will be taken after 2sec, which causes strange results. Looking further in to it with a friend of mine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.