GatsbyJSで作っているブログでページ遷移時にアニメーションが付くようにした

2020-05-28

モチベーション

GatsbyJSでブログを作っており、SPAでページ遷移が爆速なのがとても良いが、読み込みがないことで、逆にフィードバックがなくてページが変わったことに気づけないので、ページ遷移時にアニメーションを付けたかった

できあがったもの

適当にページ遷移するとファンってなるのを体験できる

※後日追記

下記 react-transition-groupgatsby-plugin-layou を使う方法でページ遷移時にアニメーションを付いたのだが、モバイル端末でスタイル崩れが発生したので、ページ遷移時のアニメーションは外した

GatsbyJSのTransition事情

gatsby-plugin-transition-link を使う方法

  • 公式で「page transition」と検索すると下記記事がヒットする

  • しかし、方針として、リンク毎に用意されたコンポーネントを使うというより、全体で一度設定をしたら意識せずとも適用される方針を取りたかったのと、インストールしてみて試してみたところ、スクロールの挙動がおかしくなったので、断念した

gatsby-plugin-page-transitions を使う方法

  • 続いて、公式のPluginsのページでTransition関係のプラグインを検索したところ、ヒットした
  • Transitionを反映させたい領域を <PageTransition> で囲むとTransitionが適用されて、インタフェースとしては直感的で良かった
  • しかし、Gatsbyのバージョンが2に上がった段階でBreaking Changeが入り、ビルドができなくなった模様
  • Gatsbyの公式が別の方法のサンプルを公開しており、そちらの方法で十分である旨が示されており、このプラグインはGatsby 1のみをサポートしていることが示されている
  • 作者的にアップデートはしないからそっちの方法に従ってね、という意図を感じた
  • ということで、こちらのプラグインを使う方法は断念した

gatsby-v2-plugin-page-transitions を使う方法

  • 上記のプラグインをForkして、Gatsby 2対応させたもの
  • インストールしてみたところ、上手く動作をした
  • しかし、WARNINGを消すためのPRがずっとマージされていなかったり、READMEが gatsby-plugin-page-transitions のもののままになっていて、Installコマンドが gatsby-plugin-page-transitions 向けのものになっていて、誤りがあったりと、保守されていない感が否めず、今後Breaking Changeが入ったタイミングで運用が厳しくなりそうだった
  • あと、個人的には、 gatsby-plugin-xxx という命名規則に従わず、間に v2 を入れてきている命名が少し気に食わなかった
  • ということで、こちらのプラグインを使う方法は断念した

react-transition-groupgatsby-plugin-layou を使う方法

やったこと

  • ということで、上記のサンプルを元にやったことを示していく
  • react-transition-groupgatsby-plugin-layout をインストール
console
$ npm i -S react-transition-group gatsby-plugin-layout
  • ちなみに、 Gatsby 2からLayoutの構造の変更があり、ページ遷移時のTransitionを実現するには gatsby-plugin-layout を入れざるを得ない

  • gatsby-config.jsgatsby-plugin-layout を追加
gatsby-config.js
module.exports = {
  ...
  plugins: [
    ...
    "gatsby-plugin-layout",
  • Transitionコンポーネントを用意

src/components/transition.js
import React from "react"
import {
  TransitionGroup,
  Transition as ReactTransition,
} from "react-transition-group"

const timeout = 250
const getTransitionStyles = {
  entering: {
    position: `absolute`,
    opacity: 0,
  },
  entered: {
    transition: `opacity ${timeout}ms ease-in-out`,
    opacity: 1,
  },
  exiting: {
    transition: `opacity ${timeout}ms ease-in-out`,
    opacity: 0,
  },
}

class Transition extends React.PureComponent {
  render() {
    const { children, location } = this.props

    return (
      <TransitionGroup>
        <ReactTransition
          key={location.pathname}
          timeout={{
            enter: timeout,
            exit: timeout,
          }}
        >
          {status => (
            <div
              style={{
                ...getTransitionStyles[status],
              }}
            >
              {children}
            </div>
          )}
        </ReactTransition>
      </TransitionGroup>
    )
  }
}

export default Transition
  • Layoutを実装

    • 上記で作成したTransitionを読み込んで使う
    • gatsby-plugin-layout の方で、 src/layouts/index.js のファイルを見にいくようになっているので、そちらの命名に従ってファイルを追加した
    • 各ページのコンポーネントをこのLayoutコンポーネントでラップしてくれるので、全ページで共通の処理を入れたい時もここに記述すると良い
    • HeaderなどをTransitionさせたくない場合は、下記のようにすると良い
src/layouts/index.js
const Layout = ({ children, location }) => (
  <>
    <Header />
    <Transition location={location}>
      {children}
    </Transition>
  </>
)

export default Layout
  • 元のLayoutコンポーネントの記述を削除
  • この時点でTransitionが適用されるようになっているのだが、遷移する前にスクロールをしていた場合、スクロールをトップに戻す処理が実行されたあとにTransitionが発生するので、挙動に違和感がある
  • そのため、下記記事に従って、 gatsby-browser.js にスクロールをトップに戻す処理を遅延させる処理を追加した

gatsby-browser.js
const transitionDelay = 250

export function shouldUpdateScroll({
  routerProps: { location },
  getSavedScrollPosition,
}) {
  if (location.action === "PUSH") {
    window.setTimeout(() => window.scrollTo(0, 0), transitionDelay)
  } else {
    const savedPosition = getSavedScrollPosition(location)
    window.setTimeout(
      () => window.scrollTo(...(savedPosition || [0, 0])),
      transitionDelay
    )
  }
  return false
}
  • この処理を追加することで、Transitionのタイミングとスクロールをトップに戻す処理が揃って、きれいに遷移できるようになった

※後日追記

上記 react-transition-groupgatsby-plugin-layou を使う方法でページ遷移時にアニメーションを付いたのだが、モバイル端末でスタイル崩れが発生したので、ページ遷移時のアニメーションは外した

おわりに

  • ブログが少しずついい感じになってきた
  • 次はアイキャッチあたりを整えていきたい

キクナントカ

ソフトウェアエンジニアをしています。趣味でボードゲームを制作したり、個人開発でNakamyというサービスを開発しています。詳しくはこちら