Asma Binta Younus
Asma Binta Younus

Reputation: 261

Javascript Modal Animation not Working When Close

I've a Simple javascript modal that I've collected from W3 Schools. It's easy and light. But the fact is, when I click on modal button, it appears with slide up animation and also an overlay animation. But when click on close button or click outside, modal get disappear or close without any animation. I want to add an animation on modal closing time. That's mean, there will be an animation on Both, modal appear and disappearing time. With overlay, like appear time. How can Indo it....?

// Get the modal
var modal = document.getElementById("myModal");

// Get the button that opens the modal
var btn = document.getElementById("myBtn");

// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];

// When the user clicks the button, open the modal 
btn.onclick = function() {
  modal.style.display = "block";
}

// When the user clicks on <span> (x), close the modal
span.onclick = function() {
  modal.style.display = "none";
}

// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
  if (event.target == modal) {
    modal.style.display = "none";
  }
}
/* The Modal (background) */

.modal {
  display: none;
  /* Hidden by default */
  position: fixed;
  /* Stay in place */
  z-index: 1;
  /* Sit on top */
  left: 0;
  top: 0;
  width: 100%;
  /* Full width */
  height: 100%;
  /* Full height */
  overflow: auto;
  /* Enable scroll if needed */
  background-color: rgb(0, 0, 0);
  /* Fallback color */
  background-color: rgba(0, 0, 0, 0.4);
  /* Black w/ opacity */
  -webkit-animation-name: fadeIn;
  /* Fade in the background */
  -webkit-animation-duration: 0.4s;
  animation-name: fadeIn;
  animation-duration: 0.4s
}


/* Modal Content */

.modal-content {
  position: fixed;
  bottom: 0;
  background-color: #fefefe;
  width: 100%;
  -webkit-animation-name: slideIn;
  -webkit-animation-duration: 0.4s;
  animation-name: slideIn;
  animation-duration: 0.4s
}


/* The Close Button */

.close {
  color: white;
  float: right;
  font-size: 28px;
  font-weight: bold;
}

.close:hover,
.close:focus {
  color: #000;
  text-decoration: none;
  cursor: pointer;
}

.modal-header {
  padding: 2px 16px;
  background-color: #5cb85c;
  color: white;
}

.modal-body {
  padding: 2px 16px;
}

.modal-footer {
  padding: 2px 16px;
  background-color: #5cb85c;
  color: white;
}


/* Add Animation */

@-webkit-keyframes slideIn {
  from {
    bottom: -300px;
    opacity: 0
  }
  to {
    bottom: 0;
    opacity: 1
  }
}

@keyframes slideIn {
  from {
    bottom: -300px;
    opacity: 0
  }
  to {
    bottom: 0;
    opacity: 1
  }
}

@-webkit-keyframes fadeIn {
  from {
    opacity: 0
  }
  to {
    opacity: 1
  }
}

@keyframes fadeIn {
  from {
    opacity: 0
  }
  to {
    opacity: 1
  }
}
<h2>Bottom Modal</h2>

<!-- Trigger/Open The Modal -->
<button id="myBtn">Open Modal</button>

<!-- The Modal -->
<div id="myModal" class="modal">

  <!-- Modal content -->
  <div class="modal-content">
    <div class="modal-header">
      <span class="close">&times;</span>
      <h2>Modal Header</h2>
    </div>
    <div class="modal-body">
      <p>Some text in the Modal Body</p>
      <p>Some other text...</p>
    </div>
    <div class="modal-footer">
      <h3>Modal Footer</h3>
    </div>
  </div>

</div>

Updated code:

// Get the modal
var modal = document.getElementById("myModal");

// Get the button that opens the modal
var btn = document.getElementById("myBtn");

// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];

// When the user clicks the button, open the modal 
btn.onclick = function() {
  modal.style.display = "block";
}

// When the user clicks on <span> (x), close the modal
span.onclick = function() {
  modal.style.display = "none";
}

// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
  if (event.target == modal) {
    modal.style.display = "none";
  }
}

function closeModal() {
  modal.classList.add('animate-out');

  modal.addEventListener('animationend', function() {
    modal.style.display = "none";
    modal.classList.remove('animate-out');
  }, {
    once: true
  });
}

span.onclick = closeModal;
window.onclick = function(event) {
  if (event.target.closest('#myModal') === null) {
    closeModal();
  }
};
/* The Modal (background) */

.modal {
  display: none;
  /* Hidden by default */
  position: fixed;
  /* Stay in place */
  z-index: 1;
  /* Sit on top */
  left: 0;
  top: 0;
  width: 100%;
  /* Full width */
  height: 100%;
  /* Full height */
  overflow: auto;
  /* Enable scroll if needed */
  background-color: rgb(0, 0, 0);
  /* Fallback color */
  background-color: rgba(0, 0, 0, 0.4);
  /* Black w/ opacity */
  -webkit-animation-name: fadeIn;
  /* Fade in the background */
  -webkit-animation-duration: 0.4s;
  animation-name: fadeIn;
  animation-duration: 0.4s
}


/* Modal Content */

.modal-content {
  position: fixed;
  bottom: 0;
  background-color: #fefefe;
  width: 100%;
  -webkit-animation-name: slideIn;
  -webkit-animation-duration: 0.4s;
  animation-name: slideIn;
  animation-duration: 0.4s
}


/* The Close Button */

.close {
  color: white;
  float: right;
  font-size: 28px;
  font-weight: bold;
}

.close:hover,
.close:focus {
  color: #000;
  text-decoration: none;
  cursor: pointer;
}

.modal-header {
  padding: 2px 16px;
  background-color: #5cb85c;
  color: white;
}

.modal-body {
  padding: 2px 16px;
}

.modal-footer {
  padding: 2px 16px;
  background-color: #5cb85c;
  color: white;
}


/* Add Animation */

@-webkit-keyframes slideIn {
  from {
    bottom: -300px;
    opacity: 0
  }
  to {
    bottom: 0;
    opacity: 1
  }
}

@keyframes slideIn {
  from {
    bottom: -300px;
    opacity: 0
  }
  to {
    bottom: 0;
    opacity: 1
  }
}

@-webkit-keyframes fadeIn {
  from {
    opacity: 0
  }
  to {
    opacity: 1
  }
}

@keyframes fadeIn {
  from {
    opacity: 0
  }
  to {
    opacity: 1
  }
}

.modal.animate-out {
  animation-name: fadeOut;
}

.modal.animate-out .modal-content {
  animation-name: slideOut;
}

@keyframes fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

@keyframes slideOut {
  from {
    transform: translate3d(0, 300px, 0);
  }
  to {
    transform: translate3d(0, 0, 0);
  }
}
<h2>Bottom Modal</h2>

<!-- Trigger/Open The Modal -->
<button id="myBtn">Open Modal</button>

<!-- The Modal -->
<div id="myModal" class="modal">

  <!-- Modal content -->
  <div class="modal-content">
    <div class="modal-header">
      <span class="close">&times;</span>
      <h2>Modal Header</h2>
    </div>
    <div class="modal-body">
      <p>Some text in the Modal Body</p>
      <p>Some other text...</p>
    </div>
    <div class="modal-footer">
      <h3>Modal Footer</h3>
    </div>
  </div>

</div>

Upvotes: 1

Views: 1183

Answers (1)

Emiel Zuurbier
Emiel Zuurbier

Reputation: 20944

The way your "in" animation works is by first changing the display property to block which renders the element visible. That also triggers the animation that is set on the modal.

The "out" animation has to work in the reverse order. First you have to animate the modal out. Whenever the animation is finished change the display property to none.

First define the animation. It should be the reverse keyframes of fadeIn and slideIn.

@keyframes fadeOut {
  from {
    opacity: 1;
  } 
  
  to {
    opacity: 0;
  }
}

@keyframes slideOut {
  from {
    transform: translate3d(0, 300px, 0);
  } 
  
  to {
    transform: translate3d(0, 0, 0);
  }
}

Also add a class that uses this animation. That way we can add the animation the .modal to overwrite the style.

.modal.animate-out {
  animation-name: fadeOut;
}

.modal.animate-out .modal-content {
  animation-name: slideOut;
}

To trigger the animation you'll only need to add the animate-out class we've just created to the modal once you click the close button. Then immediately add an event listener that listens for the animationend event. This event will trigger whenever the animation has finished, which in this case is our fade out animation.

After it finishes set display to none and remove the animate-out class from the modal to reset the animation so that a fade in can happen next time we show the modal. The { once: true } part ensures that this event is only listened to once. This is important since there are multiple animations but we only want the display: none and removal of the animate-out class to happen on the fade out animation.

// Get the modal
var modal = document.getElementById("myModal");

// Get the button that opens the modal
var btn = document.getElementById("myBtn");

// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];

// When the user clicks the button, open the modal 
btn.onclick = function() {
  modal.style.display = "block";
}

function closeModal() {
  modal.classList.add('animate-out');

  modal.addEventListener('animationend', function() {
    modal.style.display = "none";
    modal.classList.remove('animate-out');
  }, { once: true });
}

span.onclick = closeModal;

document.onclick = function(event) {
  if (event.target.matches('#myModal')) {
    closeModal();
  }
};
/* The Modal (background) */

.modal {
  display: none;
  position: fixed;
  z-index: 1;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow: auto;
  background-color: rgb(0, 0, 0);
  background-color: rgba(0, 0, 0, 0.4);
  animation-name: fadeIn;
  animation-duration: 0.4s
}

.modal.animate-out {
  animation-name: fadeOut;
}

.modal-content {
  position: fixed;
  bottom: 0;
  background-color: #fefefe;
  width: 100%;
  animation-name: slideIn;
  animation-duration: 0.4s
}

.modal.animate-out .modal-content {
  animation-name: slideOut;
}

.close {
  color: white;
  float: right;
  font-size: 28px;
  font-weight: bold;
}

.close:hover,
.close:focus {
  color: #000;
  text-decoration: none;
  cursor: pointer;
}

.modal-header {
  padding: 2px 16px;
  background-color: #5cb85c;
  color: white;
}

.modal-body {
  padding: 2px 16px;
}

.modal-footer {
  padding: 2px 16px;
  background-color: #5cb85c;
  color: white;
}

@keyframes slideIn {
  from {
    transform: translate3d(0, 300px, 0);
  }
  to {
    transform: translate3d(0, 0, 0);
  }
}

@keyframes slideOut {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(0, 300px, 0);
  }
}

@keyframes fadeIn {
  from {
    opacity: 0
  }
  to {
    opacity: 1
  }
}

@keyframes fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
<h2>Bottom Modal</h2>

<!-- Trigger/Open The Modal -->
<button id="myBtn">Open Modal</button>

<!-- The Modal -->
<div id="myModal" class="modal">
  <div class="modal-content">
    <div class="modal-header">
      <span class="close">&times;</span>
      <h2>Modal Header</h2>
    </div>

    <div class="modal-body">
      <p>Some text in the Modal Body</p>
      <p>Some other text...</p>
    </div>

    <div class="modal-footer">
      <h3>Modal Footer</h3>
    </div>
  </div>
</div>

Upvotes: 2

Related Questions