PageTransition
というコンポーネントを使うと、React アプリケーション上でページ間のトランジションを実現できます。
例えば、ページ遷移をする際に一旦フェードアウトし、遷移後にフェードインして表示するといった具合です。
Next.js にも next-page-transitions というライブラリが存在し、.page-transition-enter
、.page-transition-enter-active
、.page-transition-exit
、.page-transition-exit-active
などのクラスをつけることで、 CSS アニメーションを行うことが可能です。
ただし、ページ間の CSS の transition でうまくできないことがあります。
前述のフェードイン・フェードアウトであれば実現が出来ますが、トップページから下位ページに遷移したときにヘッダーが小さくなるといったアニメーションを行おうとするとうまくいきません。
理由としては、page
以下にコンポーネントを配置して各ページを定義している場合、ページの切り替え時に一旦 #__next
以下の HTML エレメントが除去され、再びマウントされるためです。ということで、一見 transition
の設定が出来そうに思えてもうまく動作しないのです。
大雑把な流れをページのトランジションに焦点を当てて書いてみると
- ページが表示される
Link
で定義されたリンクボタンをクリック#__next
以下の HTML エレメントが除去- リンク先のコンポーネントがマウント
というような順になります。
ではどうしたらいいのでしょうか。
僕は、以下のように実装することで実現することが出来ました。
- 状態管理の機構を用意 (今回は unstated を使っています)
- ページのレイアウト状態を管理する変数などをアプリケーションの状態として設定
Link
で定義されたリンクボタンをクリック- ページ遷移時にはアニメーションさせず、componentDidMount 時にページ遷移後にリンク元のレイアウトをアプリケーションの状態より復元
- 復元時に componentDidUpdate が走るので、そこでこのページで設定したいレイアウトの状態に変更
- アニメーションが行われる
実際のコードはこんな感じですね。
componentDidMount() {
this.props.model.setLayout(this.props.model.state.layout)
}
componentDidUpdate() {
if(this.props.model.state.layout !== Enum.layout.header.TOP) {
this.props.model.setLayout(Enum.layout.header.TOP)
}
}
componentDidMount
時にレイアウトを変更してしまうと、リンク元のレイアウト状態がないため、transition
も発生しなくなるので、このようにしました。他にもやり方があるかもしれませんが、現状これでうまくいっているので、よしとします。
ということで、このサイトのトップページから下位階層のページに遷移するときなどに、ヘッダー部分の遷移アニメーションを追加してみました。
ARTICLES
AUTHOR

原 一浩
カンソクインダストリーズ代表 / グレーティブ合同会社代表
1998年に独立し、同年、ウェブデザイン専門のメールメディア DesignWedgeの発行を開始。Webデザイン業の傍ら、海外のWebデザインに関する情報発信を行う。
雑誌への寄稿多数。主な著書に『はじめてのフロントエンド開発』『プロセスオブウェブデザイン』、『Play framework徹底入門』、『ウェブデザインコーディネートカタログ』など。自社製のWebデザインのクロール&キャプチャシステムvaqumをベースに、様々なリサーチを行っている。Web 検定プロジェクトメンバー。