【JavaScript】ページ遷移アニメーションを簡単に実装する方法(フェードイン・アウト)

JavaScript

JavaScriptでページ遷移アニメーションを簡単に実装する方法を紹介します。
フェードイン・アウトのページ遷移アニメーションを作成しますが、CSSで制御するので、どんなものでもカスタマイズ可能です。

ページ遷移アニメーションのCSSソースコード


@keyframes fadeOut {
  0% {
    opacity: 1 !important;
    visibility: visible;
  }
  100% {
    opacity: 0 !important;
    visibility: hidden;
  }
}

上のように単純なfadeOutクラスのつけ外しをJavaScriptでコントロールします。

ページ遷移の流れ

まず大枠として流れとしては、ページ遷移前にフェードアウトするfadeOutクラスを付与して、フェードアウトさせます。
そして、HTMLに予め付与しておいたfadeoutクラスをページ読み込み時に取り除くことで、ページ遷移のアニメーションが可能になります。

ページ遷移前にfadeOutクラスを付与するJavaScriptソースコード


/*
 * fadeoutクラスをつけて、ページ読み込み時に削除している
 * jsPageTransitionクラスをhtmlにつけることで#つきも選択可能
 * safariではブラウザバックでキャッシュ問題があるので下部にその対策を実施
 * 
 */

const wrapper = document.querySelector(".wrapper");
const pageTransitionDOMClass = 'jsPageTransition'; //pageTransitionを適用したい#つきのaタグにつけるクラス
const linkEls = [
  ...document.querySelectorAll('a:not([href*="#"]):not([target])'),
  ...document.querySelectorAll('.jsPageTransition'),
];

const currentHostName = window.location.hostname; //URL内だったらと条件にする

function addFadeout(url) {
  wrapper.classList.add("fadeout");
  setTimeout(() => {
    window.location = url;
  }, 300);
}

// setTimeoutのdelayはbaseのwrapper::afterのtransitionと合わせる
linkEls.forEach((linkEl) => {
  linkEl.addEventListener("click", (e) => {
    // command or control+クリックのときは処理しない
    if ((e.ctrlKey && !e.metaKey) || (!e.ctrlKey && e.metaKey)) return;

    e.preventDefault(); //cancel navigate
    e.stopPropagation(); //menuなどに伝搬されて挙動が変わる場合があるので防止
    let url = linkEl.getAttribute("href");
    if (url !== "" && url.indexOf(currentHostName)) {
      addFadeout(url);
    }
  }, false);
});


// SafariでブラウザバックするとJSなどが解除されていない問題【bfcache】の対策
強制リロード
window.addEventListener('pageshow', function (event) {
  if (event.persisted) {
    // bfcache発動時の処理
    window.location.reload();
  }
});

コードが長いので、分割して説明します。

要素を指定する


const wrapper = document.querySelector(".wrapper");
const pageTransitionDOMClass = 'jsPageTransition'; //pageTransitionを適用したい#つきのaタグにつけるクラス
const linkEls = [
  ...document.querySelectorAll('a:not([href*="#"]):not([target])'),
  ...document.querySelectorAll('.jsPageTransition'),
];

bodyタグの直下にwrapperクラスのついたdivタグを用意して、それを取得します。
また、クリックしてページ遷移アニメーションを適用させたいリンクを指定します。
aタグをクリックした場合に発火させると、ハッシュがついている内部リンクまでフェードアウトしてしまい、真っ白な画面になるため、ハッシュは削除します。
また、ハッシュが先頭ではなく、途中についているパスでも、ページ遷移させたい場合があるので、それは個別にjsPageTransitionクラスを付与して、それもページ遷移アニメーションが適用されるように、linkElsの配列に格納します。

URL内だったらフェードアウトするように条件を付与する


const currentHostName = window.location.hostname; //URL内だったらと条件にする

他のサイトに飛んでもフェードアウトしてしまった場合、画面が真っ白になるので、同じドメイン内の場合のみフェードアウトするようにします。
window.location.hostnameでホスト名を取得できます。
そのホスト名の中であれば、fadeOutクラスをつけるという処理にします。

フェードアウトのクラスを付与する関数


function addFadeout(url) {
  wrapper.classList.add("fadeout");
  setTimeout(() => {
    window.location = url;
  }, 300);
}

fadeoutを付与して、その後0.3秒後にwindowのlocationに渡されたurlを代入して移動します。

それぞれのリンクにイベントを登録する


linkEls.forEach((linkEl) => {
  linkEl.addEventListener("click", (e) => {
    // command or control+クリックのときは処理しない
    if ((e.ctrlKey && !e.metaKey) || (!e.ctrlKey && e.metaKey)) return;

    e.preventDefault(); //cancel navigate
    e.stopPropagation(); //menuなどに伝搬されて挙動が変わる場合があるので防止
    let url = linkEl.getAttribute("href");
    if (url !== "" && url.indexOf(currentHostName)) {
      addFadeout(url);
    }
  }, false);
});

command or control+クリックのときは、新規タブで開くことができるので、そのキーが押されているときはイベントが発火しないようにします。

そして、リンクの通常動作をしないように、preventDefault()を実行します。
いったんhref属性のパスだけを取得して、urlという変数に格納します。
そのurlが空でないときでかつ、ホスト名が同じときのみ、うえのフェードアウトのクラスを付与する関数を実行します。

SafariでブラウザバックするとJSなどが解除されていない問題【bfcache】の対策


// SafariでブラウザバックするとJSなどが解除されていない問題【bfcache】の対策
強制リロード
window.addEventListener('pageshow', function (event) {
  if (event.persisted) {
    // bfcache発動時の処理
    window.location.reload();
  }
});

こちらの対策に関しては、詳しくは【JavaScript】Safariでブラウザバックすると正しく動作しない【bfcache】の対策を参照してみてください。

fadeOUtクラスを取り外す関数


document.addEventListener('DOMContentLoaded', () => {
  if(wrapper.classList.contains('fadeout')) {
    wrapper.classList.remove('fadeout');
  }
});

DOMContentLoadedのタイミングで、wrapperという変更に、fadeOutクラスがある場合、取り除くという処理です。

これでページが遷移アニメーションができます。