Home > Back-end >  Animate a details tag when closing
Animate a details tag when closing

Time:11-14

I am working on a website for my history project and I came across a problem. I tried to animate a details tag but nothing seems to be working. Here is the code I used for the opening animation:

@keyframes open {
  0% {
    opacity: 0;
    transform: translateY(-1vw);
  }
  100% {
    opacity: 1;
    margin-left: 0px
  }
}

details[open] summary~* {
  animation: open .5s cubic-bezier(0.785, 0.135, 0.15, 0.86);
}
<details>
  <summary>Cfare do te mesosh gjate ketij materiali:</summary>
  <ul>
    <li>
      <p>Shqiperia gjate luftes se pare boterore</p>
    </li>
    <li>
      <p>Shqiperia mes lufterave boterore</p>
    </li>
    <li>
      <p>Shqiperia gjate luftes se dyte boterore</p>
    </li>
  </ul>
</details>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

It is basically a simple fade in animation and I would love to do a fade out one as well!

Thanks in advance!

CodePudding user response:

Hi and welcome to stack overflow!

I went ahead and added a class called fade-in to support the animations per each browser. I gave that class to each of the <li> 's in your animation. Feel free to change as you desire, but this should get you a good get starting point for your animation.

@keyframes fadeIn {
  0% {
    opacity: 0;
    transform: translateY(-1vw);
  }
  100% {
    opacity: 1;
    margin-left: 0px
  }
}


details[fadeIn] summary ~ * {
  animation: open .5s cubic-bezier(0.785, 0.135, 0.15, 0.86);
}

.fade-in {
  animation: fadeIn ease 2s;
  -webkit-animation: fadeIn ease 2s;
  -moz-animation: fadeIn ease 2s;
  -o-animation: fadeIn ease 2s;
  -ms-animation: fadeIn ease 2s;
}
<details>
  <summary>Cfare do te mesosh gjate ketij materiali:</summary>
  <ul>
    <li class="fade-in">
      <p>Shqiperia gjate luftes se pare boterore</p>
    </li>
    <li class="fade-in">
      <p>Shqiperia mes lufterave boterore</p>
    </li>
    <li class="fade-in">
      <p>Shqiperia gjate luftes se dyte boterore</p>
    </li>
  </ul>
</details>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

It took me a while to figure it out, but it is an interesting question.

When you open the details element, its content - by definition - becomes visible. This is why every animation you apply is visible. However, when you close the details element, its content - by definition - becomes invisible, immediately. So even though every animation you try to apply will actually occur, it will simply not be visible.

So we need to tell the browser to delay hiding the elements, apply the animation, and only then hide the elements. Let's use some JS for that.

We need to capture when the user toggles the details element. Supposedly, the relevant event would be toggle. However, this event is fired only after the browser hides everything. So we will actually go with the click event, wich fires before the hiding happens.

const details = document.querySelector("details");
details.addEventListener("click", function(e) {
  if (details.hasAttribute("open")) { // since it's not closed yet, it's open!
    e.preventDefault(); // stop the default behavior, meaning - the hiding
    details.classList.add("closing"); // add a class which apply the animation in CSS
    setTimeout(() => { // only after the animation finishes, continue
      details.removeAttribute("open"); // close the element
      details.classList.remove("closing");
    }, 400);
  }
});
@keyframes open {
  0% {
    opacity: 0
  }
  100% {
    opacity: 1
  }
}

/* closing animation */
@keyframes close {
  0% {
    opacity: 1
  }
  100% {
    opacity: 0
  }
}

details[open] summary~* {
  animation: open .5s;
}

/* closing class */
details.closing summary~* {
  animation: close .5s;
}
<details>
  <summary>Cfare do te mesosh gjate ketij materiali:</summary>
  <ul>
    <li>
      <p>Shqiperia gjate luftes se pare boterore</p>
    </li>
    <li>
      <p>Shqiperia mes lufterave boterore</p>
    </li>
    <li>
      <p>Shqiperia gjate luftes se dyte boterore</p>
    </li>
  </ul>
</details>
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

Note that time durations are not guaranteed to be accurate, not in CSS and not in JS. This is why I have set the JS timeout to be just a little bit lower than the CSS animation duration (400ms vs 500ms), so we are sure the animation ends just a bit after we're hiding the elements, so we don't get any flickering.

  • Related