Create Staggered Text Animation with Tailwind CSS and React
記事は上記記事を意訳したものです。
※当ブログでの翻訳記事は元サイト様に許可を得て掲載しています。
Linearのランディングページに似た、React と Tailwind CSS を使って作成されたスタガーテキストアニメーションを実装してみましょう!
Vite React アプリの設定と Tailwind CSS のセットアップ
最初に、npx create vite app
コマンドを使用して、Vite React アプリを作成し、ライブラリとして React を選択します。公式の Tailwind CSS ドキュメントに従って、6つの簡単なステップを実行し、プロジェクトに Tailwind をセットアップします。
npm run dev
でデベロップメントサーバーを起動すると、アプリが localhost:5173
で実行されるはずです。
代わりに、Vite の代替として Next.js または Remix を使うこともできます。
マークアップの生成
Figma のこのモックアップから出発し、Builder.io の Figma プラグインの Visual Copilot を使って、デザインを React + Tailwind のコードに変換しました。
Figma で「Generate」をクリックし、生成されたコードをコードベースにコピー&ペーストしました。私は Hero.tsx
という新しいファイルにそのコードを配置しました。
スライドインアニメーションの追加
Tailwind のアニメーション機能を強化するため、tailwind.config.js
ファイルの theme.extend.animation
と theme.extend.keyframes
を変更しました。
export default { content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], theme: { extend: { keyframes: { slidein: { from: { opacity: "0", transform: "translateY(-10px)", }, to: { opacity: "1", transform: "translateY(0)", }, }, }, animation: { slidein: "slidein 1s ease 300ms", }, }, }, plugins: [], };
この コードスニペットでは、新しい slidein
アニメーションを定義しています。from
キーフレームでは、コンテンツが不透明度 0%で最終位置よりも少し上にあり、to
キーフレームでは、不透明度 100%で最終位置になります。
このアニメーションは 1 秒かけて 'ease' タイミング関数で実行され、300ms の遅延があります。
この animate-slidein
クラスをヒーローテキストを表す 4 つの要素に適用します。
<!-- 要素 1 --> <div className="animate-slidein ..."> <div className="...">Introducing Linear Asks</div> <img loading="lazy" src="..." className="..." alt="Icon" /> </div> <!-- 要素 2 --> <h1 className="animate-slidein ..."> Linear is a better way <br /> to build products </h1> <!-- 要素 3 --> <p className="animate-slidein ..."> Meet the new standard for modern software development. <br /> Streamline issues, sprints, and product roadmaps. </p> <!-- 要素 4 --> <div className="animate-slidein ..."> <div className="...">Get started</div> <img loading="lazy" src="..." className="..." alt="Arrow icon" /> </div>
アニメーションのスタガー
アニメーションが実行されますが、すべての要素が一度にスライドインしています。スタガー効果を作るため、Tailwind の設定で slidein
アニメーションの 4 つのバリアントを定義し、異なる遅延を設定します。
animation: { slidein300: "slidein 1s ease 300ms", slidein500: "slidein 1s ease 500ms", slidein700: "slidein 1s ease 700ms", },
Hero コンポーネントの className
をこれらの新しいアニメーションバリアントに更新します。
<!-- 要素 1 --> <div className="animate-slidein300 ..."> <div className="...">Introducing Linear Asks</div> <img loading="lazy" src="..." className="..." alt="Icon" /> </div> <!-- 要素 2 --> <h1 className="animate-slidein300 ..."> Linear is a better way <br /> to build products </h1> <!-- 要素 3 --> <p className="animate-slidein500 ..."> Meet the new standard for modern software development. <br /> Streamline issues, sprints, and product roadmaps. </p> <!-- 要素 4 --> <div className="animate-slidein700 ..."> <div className="...">Get started</div> <img loading="lazy" src="..." className="..." alt="Arrow icon" /> </div>
これでアニメーションがきれいにスタガーするようになりましたが、アニメーション開始前に要素が表示されてしまう問題があります。これを修正するため、opacity-0
クラスを追加して、初期状態で要素が非表示になるようにします。
<!-- 要素 1 --> <div className="animate-slidein300 opacity-0 ..."> <div className="...">Introducing Linear Asks</div> <img loading="lazy" src="..." className="..." alt="Icon" /> </div> <!-- 要素 2 --> <h1 className="animate-slidein300 opacity-0 ..."> Linear is a better way <br /> to build products </h1> <!-- 要素 3 --> <p className="animate-slidein500 opacity-0 ..."> Meet the new standard for modern software development. <br /> Streamline issues, sprints, and product roadmaps. </p> <!-- 要素 4 --> <div className="animate-slidein700 opacity-0 ..."> <div className="...">Get started</div> <img loading="lazy" src="..." className="..." alt="Arrow icon" /> </div>
スタガーアニメーションが期待通りに動作しますが、アニメーション後にヒーローテキスト要素がすべて消えてしまいます。これを修正するため、animation-fill-mode: forwards
を指定して、要素がアニメーションの最後のキーフレームのスタイルを維持するようにします。
animation: { slidein300: "slidein 1s ease 300ms forwards", slidein500: "slidein 1s ease 500ms forwards", slidein700: "slidein 1s ease 700ms forwards", },
これでアニメーションがきれいにスタガーするようになりました。
CSS 変数を使ったリファクタリング
コードを最適化するため、CSS 変数を使ってカスタムアニメーションをリファクタリングします。デフォルト値が 0ms の --slidein-delay
変数を導入します。
animation: { slidein: "slidein 1s ease var(--slidein-delay, 0) forwards", }
次に、この変数を Hero コンポーネントに適用します。
<!-- 要素 1 --> <div className="animate-slidein opacity-0 [--slidein-delay:300ms] ..."> <div className="...">Introducing Linear Asks</div> <img loading="lazy" src="..." className="..." alt="Icon" /> </div> <!-- 要素 2 --> <h1 className="animate-slidein opacity-0 [--slidein-delay:300ms] ..."> Linear is a better way <br /> to build products </h1> <!-- 要素 3 --> <p className="animate-slidein opacity-0 [--slidein-delay:500ms] ..."> Meet the new standard for modern software development. <br /> Streamline issues, sprints, and product roadmaps. </p> <!-- 要素 4 --> <div className="animate-slidein opacity-0 [--slidein-delay:700ms] ..."> <div className="...">Get started</div> <img loading="lazy" src="..." className="..." alt="Arrow icon" /> </div>
以上が、React と Tailwind CSS を使って Linear のランディングページに似たスタガーテキストアニメーションを実装する手順です。