今回は【barba.js(v2)】を使ってシームレスなページ遷移で遷移時にアニメーションをつけるまで挑戦してみます。
【barba.js(v2)】を使ってページ遷移にアニメーションを実装するデモもご紹介しています。
IE11にも対応できる方法を記載していますので合わせてご確認ください。
【barba.js(v2)】ってなに?
barba.jsは非同期で画面遷移ができるJSライブラリです。(v2はバージョン2)
ブラウザのHTTPリクエストを最小限に抑えて、ページ遷移の遅延を減らしてシームレスな画面遷移を実装することができます。
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>
以下が初期化処理のコードです。
<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() { // 次のページに入った時のアニメーションを設定する }, }, ],});
その他にもフックにできるタイミングがいくつもあります。
フック名 | 内容 |
---|---|
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については以下もご参考にしてください。
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が必要です。
以下を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() {}, }, ],});
以下のように「leave」「enter」といったフックの箇所を修正することで無事IE11でも動作しました。
barba.init({ transitions: [ { leave: function () {}, enter: function () {}, }, ],});
作成したデモ
4ページを遷移するだけの簡単なデモですが、シームレスな画面遷移が実現できました。 (IE11でも動作します)
最後に
今回は【barba.js(v2)】を使ってシームレスな画面遷移を実装してみました。
確かにbarba.jsを使用することで画面遷移のストレスもなく、シームレスなアニメーションも魅力的です。
しかし実装のデメリットやコストもすごく多いと感じました。。 ポートフォリオなどページ数の少ないサイトで活用してみたいと思います。