Next.jsでのWebサイト制作 #2では、共通機能(React hooks × css animateによるアニメーション機能)の実装を紹介をしたいと思います。
#1はこちらから読めます。
↓↓↓
アニメーションの共通化
今回制作したWebサイトでは、以下2つのアニメーションをあらゆる部分で共通使用しています。
- 画面更新後の秒数をトリガーに発火するアニメーション
- スクロールをトリガーに発火するアニメーション
今回はこれらのアニメーションの実装方法を紹介します。
また、前回のレイアウト同様、上記アニメーションは共通機能になるため、app/componentsの直下にAnimation.tsxを作成し、実装しました。
画面更新後の秒数をトリガーに発火するアニメーション
まずは、画面更新後の秒数をトリガーに発火するアニメーション機能の紹介です。
上記イメージの通り、トップ画面を読み込んでから数秒後に、メイン画像に被せるようにメッセージが左からスライドインして出現します。
実装方法
// time:何秒後に出現させるか, direction:要素の移動方向
export const TimeFadeIn = ({ children, time, direction }: any) => {
// 要素の出現を管理
const [inView, setInView] = useState(false);
useEffect(() => {
// コンポーネントがマウントされた後、time秒後に inViewをtrue に設定
const timer = setTimeout(() => {
setInView(true);
}, time);
// コンポーネントがアンマウントされた際にタイマーをクリア
return () => clearTimeout(timer);
}, []);
return (
// inViewがtrueになったらopacity-100となり表示される
<div
className={`${inView ? "opacity-100" : `opacity-0 ${direction === "right" ? "translate-x-[50%]" : "translate-x-[-50%]"}`}
duration-[1s]`}
>
{children}
</div>
);
};
上記の通り、useState, useEffect, setTimeoutを組み合わせることで、
コンポーネントがマウントされてから、引数で与えられた秒数がたった際に、stateがtrueになり、それに応じてJSX内のTailwindが動的に変化するよう実装しました。
Tailwindではopacityとtranslateを動的に変化させています。
引数のdirectionは要素の移動方向を判断するためのものであり、rightの場合は"translate-x-[50%]"として右に移動 、それ以外の場合は "translate-x-[-50%]"として左に移動するようにしています。
上記により、「inView」がtrueになったら、「1秒かけて、要素を右移動しながら出現させる。」という動きを実現しています。
スクロールをトリガーに発火するアニメーション
続いて、スクロールをトリガーに発火するアニメーション機能の紹介です。
GIFだと分かりづらいかと思いますので、ぜひ実際にHPにアクセスして試してみてください。
https://ty-official-hp-14.vercel.app/
上記の通り、画面をスクロールした際に、さまざまなアニメーションとともに要素を出現させる機能を実装しました。
実装方法
// animation:アニメーションの種類, rootMargin:どのくらいスクロールした時に発火させるか
export const Animation = ({
children,
animation,
rootMargin,
}: {
children: any;
animation: string;
rootMargin: string;
}) => {
// ref要素(以下のdivタグ)がrootMarginに来た時点で、inViewがtrueになる
const { ref, inView } = useInView({
// ここに位置を設定
rootMargin: rootMargin,
// 最初の一度だけ実行
triggerOnce: true,
});
return (
<div
ref={ref}
className={`${
// inViewがtrueになったら、引数で受け取ったアニメーションを使用して要素を表示
inView ? "animate__animated animate__" + animation : "opacity-0"
} `}
>
{children}
</div>
);
};
上記の通り、css animateとreact-intersection-observerのuseInViewを組み合わせることで、スクロール状況を監視&検知し、アニメーションとともに要素を出現させるという動きを実現しています。
こちらについては、以下の記事で実装方法を詳しく説明しておりますので、ここでの説明は割愛させていただきます。
記事内のサンプルコードにおける、rootMargin:に設定する数値と、対象要素のclassNameに割り当てるanimateの種類を引数で受け取るようにして、汎用性を高めたものが上記のコードになります。
最後に
今回は、プロジェクト全体で使用している共通機能について、紹介しました。
次回はトップページの内容について、紹介したいと思います。
トップページは、three.jsで3Dモデルを表示したりと、紹介したい内容がたくさんありますので、ぜひ次回もお読みいただければ幸いです!
ありがとうございました。
p.s.
未熟エンジニアなもので、間違った技術の使い方等、たくさんしていると思います。
そんな時はコメントで教えていただけるととても嬉しいです。