Page transitions in Astro

How to create page transitions in Astro

On your pages (where your main layout is, for example), add an item that we can fade in/out upon navigation.

<div id="fader" class="fader"></div>

Add the corresponding CSS:

.fader {
  pointer-events: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: #fff;
  z-index: 999;
  animation-duration: 200ms;
  animation-timing-function: cubic-bezier(0.785, 0.135, 0.15, 0.86);
}
.fader.fade-in {
  opacity: 1;
  animation-name: fade-in;
}
.fader.fade-out {
  opacity: 0;
  animation-name: fade-out;
}
@keyframes fade-out {
    from { opacity: 1; }
      to { opacity: 0; }
}
@keyframes fade-in {
    from { opacity: 0; }
      to { opacity: 1; }
}

And finally, add some JavaScript to control the navigation. This can also go on your “main layout” page:

document.addEventListener('DOMContentLoaded', setupPageTransition);

let fader = null;

function setupPageTransition() {
  fader = document.querySelector('#fader');
  if (fader !== undefined && fader !== null) {
    // on page load, fade out the "cover"
    fader.classList.add('fade-out');
  }

  // "hijack" all page links, and delay navigation slightly so we get the "fade out" effect
  const anchors = Array.from(document.querySelectorAll('a'));
  anchors.forEach(link => {
    if (link.hostname !== window.location.hostname || link.pathname === window.location.pathname) {
      // skip internal links & external websites
    } else {
      link.addEventListener('click', fadeOut);
    }
  });
}

function fadeOut(e) {
  // Prevent immediate navigation and redirect the user after 200ms
  e.preventDefault();
  setTimeout(() => {
    window.location = e.target.href;
  }, 200);
  if (fader !== undefined && fader !== null) {
    fader.classList.add('fade-in');
  }
}