Javascript

【barba.js(v2)】を使ってシームレスなページ遷移を実装してみた

今回は【barba.js(v2)】を使ってシームレスなページ遷移で遷移時にアニメーションをつけるまで挑戦してみます。

【barba.js(v2)】を使ってページ遷移にアニメーションを実装するデモもご紹介しています。

IE11にも対応できる方法を記載していますので合わせてご確認ください。

【barba.js(v2)】ってなに?

barba.jsは非同期で画面遷移ができるJSライブラリです。(v2はバージョン2)

ブラウザのHTTPリクエストを最小限に抑えて、ページ遷移の遅延を減らしてシームレスな画面遷移を実装することができます。

https://barba.js.org/

MITライセンス

barba.jsは【Pjaxライブラリ】

barba.jsは【Pjax】という技術を利用したライブラリです。

Pjax】とは、
ブラウザの閲覧履歴を操作する【push state】
非同期通信で閲覧ページ以外から、情報を取得することができる 【ajax】 を利用したのが【Pjax】です。

barba.jsを使うことで、このPjax+画面遷移の時のコンテンツの設定や、トランジションを追加していくことができます。

デメリットも

シームレスな画面遷移は魅力的なbarba.jsですが、デメリット沢山あります。

  • 最初に閲覧したページが基準のため、相対パスの場合ずれる
  • head内の情報(meta情報)が変わらない
  • ページ遷移の時にload系のscriptは読み込まれない
  • Pjax遷移させないリンクは対象除外の処理が必要
  • その他JSプラグインを使用している場合、読み込まれない場合がある
  • Google Analyticsのページビューがカウントされない

多いですね。。しかも致命的なデメリットが多いので、しっかり対応していく必要がありそうです。

早速インストールして試していきます。

インストール

今回はCDNで「barba.js」を使用します。以下のどちらかをhtmlに読み込ませます。

<!-- unpkg -->
<script src="https://unpkg.com/@barba/core"></script>

<!-- jsdelivr -->
<script src="https://cdn.jsdelivr.net/npm/@barba/core"></script>

https://barba.js.org/docs/getstarted/install/

以下が初期化処理のコードです。

<script>
  barba.init();
</script>

これだけでも、htmlをbarba用にマークアップすれば非同期画面遷移させることができます。

次にhtmlのマークアップを見ていきます。

マークアップ

以下を非同期画面遷移させるページ全てにマークアップします。

<body data-barba="wrapper">
  <!-- <header>や<nav>など、ページ間で変化しないコンテンツをここに配置 -->

  <main data-barba="container" data-barba-namespace="top">
    <!-- ページ間で変更するコンテンツをこの中に配置します -->
  </main>

  <!-- <footer>など、ページ間で変化しないコンテンツをここに配置 -->
</body>

data-barba=”wrapper”

【data-barba=”wrapper”】ですべてのページ構造をラップさせます。
「body」タグ意外に「div」でも使用可。

data-barba=”container”

Pjaxで更新させる箇所を【data-barba=”container”】で囲みます。
この「container」で囲まれていない部分は更新されません。

data-barba-namespace=””

【data-barba-namespace】を指定することで各ページを識別させて定義できます。ページごとに処理を分ける場合に使えます。
例 「data-barba-namespace=”top”」「data-barba-namespace=”about”」

ここまでで非同期で画面遷移の実装は完了です。
次に画面遷移の時のアニメーションを実装してみます。

画面遷移のアニメーションを実装する

画面遷移のアニメーションを実装していく前に、フックとなる構文を確認していきます。初期化処理の中に【transitions】を設定していきます。「name」は任意です。

ここでベースとなる【leave】【enter】を設定します。
leave()は現在のページを離れる時の処理です。
enter()は次のページに入った時の処理です。

barba.init({
  transitions: [{
    name: 'default-transition',
    leave() {
      // 現在のページを離れる時のアニメーションを設定する
    },
    enter() {
      // 次のページに入った時のアニメーションを設定する
    }
  }]
});

その他にもフックにできるタイミングがいくつもあります。

https://barba.js.org/docs/getstarted/lifecycle/

フック名内容
beforeOnce現在のページが表示される直前
once現在のページが表示される時
afterOnce現在のページが表示された直後
before最初
beforeLeave現在のページを離れる前
leave現在のページを離れる時
afterLeave現在のページを離れた直後
beforeEnter次のページを表示する前
enter次のページを表示する時
afterEnter次のページを表示した直後
after最後

アニメーションを設定する

htmlに画面遷移のアニメーション用にマスクを作ります。マスクは共通で使えるのでcontainerの外で問題ありません。

HTML

<body data-barba="wrapper">

  <section data-barba="container" data-barba-namespace="top">
        <h1 class="title">TOP PAGE</h1>
  </section>

  <div class="mask"></div>
</body>

CSS

一応簡単ですがcssも。

.mask {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 100;
  width: 100%;
  height: 100vh;
  -webkit-transform: translateY(100%);
          transform: translateY(100%);
  background: #afafaf;
}

次にJSでアニメーションを設定していきます。
アニメーションには【anime.js】を使用します。

anime.jsについては以下もご参考にしてください。

軽量アニメーションJavascriptライブラリ【anime.js】を使ってみた

JS

barba.init({
    transitions: [{
        // 現在のページを離れる時のフック
        leave: function (data) {
            return new Promise(function (resolve, reject) {
                leaveAnimation(data.current.container);
                setTimeout(function () {
                    resolve();
                }, 800)
            });
        },
       // 次のページを表示する時のフック
        enter: function (data) {
            enterAnimation(data.next.container);
        }
    }]
});
// 現在のページを離れる時のアニメーション
function leaveAnimation(e) {
    anime.timeline().add({
        easing: 'easeOutSine',
        targets: e.querySelector('.section-01'),
        duration: 500,
        opacity: [1, 0],
        translateY: [0, '-15px']
    }).add({
        easing: 'easeOutSine',
        targets: '.mask',
        duration: 400,
        translateY: ['100%', 0]
    }, '-=200');
}
// 次のページを表示する時のアニメーション
function enterAnimation(e) {
    anime.timeline().add({
        easing: 'easeInSine',
        targets: '.mask',
        duration: 300,
        delay: 200,
        translateY: [0, '-100%']
    }).add({
        easing: 'easeInSine',
        targets: e.querySelector('.section-01'),
        duration: 400,
        opacity: [0, 1],
        translateY: ['15px', 0]
    }, '-=100');
}

遷移するコンテンツとマスクのコンテンツのアニメーションを設定しています。遷移するコンテンツはフワッと上に消えるようなアニメーションを、マスクは上に勢いよくでる感じですね。

JSアニメーション用関数

// 現在のページを離れる時のアニメーション
function leaveAnimation(e) {
    anime.timeline().add({
        easing: 'easeOutSine',
        targets: e.querySelector('.section-01'),
        duration: 500,
        opacity: [1, 0],
        translateY: [0, '-15px']
    }).add({
        easing: 'easeOutSine',
        targets: '.mask',
        duration: 400,
        translateY: ['100%', 0]
    }, '-=200');
    // animationの戻り値をpromiseに
    return animation.finished;
}
// 次のページを表示する時のアニメーション
function enterAnimation(e) {
    anime.timeline().add({
        easing: 'easeInSine',
        targets: '.mask',
        duration: 300,
        delay: 200,
        translateY: [0, '-100%']
    }).add({
        easing: 'easeInSine',
        targets: e.querySelector('.section-01'),
        duration: 400,
        opacity: [0, 1],
        translateY: ['15px', 0]
    }, '-=100');
}

barba.jsの【leave】【enter】フックに作成したアニメーションの関数を記述します。
【leave】フックは【promise】を使用して、アニメーションが終わるまで待機させます。

JSアニメーションフック

barba.init({
    transitions: [{
        // 現在のページを離れる時のフック
        leave: function (data) {
            return new Promise(function (resolve, reject) {
                leaveAnimation(data.current.container);
                setTimeout(function () {
                    resolve();
                }, 800)
            });
        },
       // 次のページを表示する時のフック
        enter: function (data) {
            enterAnimation(data.next.container);
        }
    }]
});

これでアニメーションの設定が完了しました。
以下のようなアニメーションになります。

metaタグを変更させる

baraba.jsを使用してコンテンツをシームレスに遷移させることが出来ましたが、このままではhead内のmetaタグは変更されません。(titleタグはデフォルトで更新されます)

そこで以下の関数を追加します。(jQueryを使用しています)

// head内のタグを変更
function replaceHeadTags(target) {
    var $newPageHead = $('<head />').html($.parseHTML(target.html.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0], document, true));
    var headTags = [
        "meta[name='keywords']",
        "meta[name='description']",
        "meta[property^='og']",
        "meta[property^='fb']",
        "meta[name^='twitter']",
        "meta[name='robots']",
        "meta[itemprop]",
        "link[itemprop]",
        "link[rel='prev']",
        "link[rel='next']",
        "link[rel='canonical']",
    ].join(',');
    $('head').find(headTags).remove();
    $newPageHead.find(headTags).appendTo('head');
}
barba.init({
    transitions: [{
       // 次のページを表示する直前
        beforeEnter: function (data) {
            replaceHeadTags(data.next);
        },

    }]
});

これで次のページを表示する時にhead内のmetaタグが更新されます。

Google Analyticsに情報を送信させる

以下を追記します。

//Googleアナリティクスに送信
var gaPush = function () {
    if (typeof ga === 'function') {
        ga('send', 'pageview', location.pathname);
    }
    if (typeof gtag === 'function') {
        gtag('config', 'トラッキングID', {'page_path': location.pathname});
    }
}
barba.init({
    transitions: [{
       // 次のページを表示する直前
        beforeEnter: function (data) {
            gaPush();
        },
    }]
});

リンク先が同URLの時リロードさせない処理

リンク先が同じURLの時にリロードさせたくない場合は以下をJSに追加します。(jQueryを使用しています)

// リンク先が現在と同じページの場合、リロードしない
var $links = $('a[href]');
var noLinkFunc = function (e) {
    if (e.currentTarget.href === window.location.href) {
        e.preventDefault();
        e.stopPropagation();
    }
};
$links.each(function (index, element) {
    console.log(element);
    $(element).on('click', function (e) {
        noLinkFunc(e);
    });
});

IE11に対応させる場合

barba.jsのバージョン2(v2)はPromiseやSet(),Map()、IntersectionObserverなどの技術が使用されています。そのため、IE11に対応させる場合はPolyfillが必要です。

https://barba.js.org/docs/getstarted/browser-support/

以下をbarba.jsの前に読み込ませます。

<script
  crossorigin="anonymous"
  src="https://polyfill.io/v3/polyfill.min.js?features=default%2CArray.prototype.find%2CIntersectionObserver"
></script>

Polyfillを読み込んでもIE11で動作しない?

自分の場合、Polyfillを読み込んだだけでは動作しませんでした。
「SCRIPT1003: ‘:’ がありません」というエラーがでます。

「barbaCss」だけを使用する場合はでないのですが、公式サイトの以下の構文をそのまま使用するとエラーになります。

barba.init({
  transitions: [{
    leave() {

    },
    enter() {

    }
  }]
});

https://barba.js.org/docs/getstarted/basic-transition/

以下のように「leave」「enter」といったフックの箇所を修正することで無事IE11でも動作しました。

barba.init({
  transitions: [{
    leave: function () {

    },
    enter: function () {

    }
  }]
});

作成したデモ

4ページを遷移するだけの簡単なデモですが、シームレスな画面遷移が実現できました。
(IE11でも動作します)

最後に

今回は【barba.js(v2)】を使ってシームレスな画面遷移を実装してみました。

確かにbarba.jsを使用することで画面遷移のストレスもなく、シームレスなアニメーションも魅力的です。

しかし実装のデメリットやコストもすごく多いと感じました。。
ポートフォリオなどページ数の少ないサイトで活用してみたいと思います。

参考サイト

https://barba.js.org/
https://www.evoworx.co.jp/blog/barbajs-transition/
https://notes.sharesl.net/articles/50/
https://liginc.co.jp/476913
https://www.willstyle.co.jp/blog/1722/
https://leap-in.com/ja/notes-when-you-use-barba-js-2/
https://gist.github.com/mhige/a5fe953de730afdd353e2432ace909b0#file-barba-custom-js-L22-L45