Webページを開いたときに、じわっとテキストが徐々にフェードインして表示されるアニメーションをなんとかCSSのみで表現できないか試してみました。

今回は、左から右、右から左、上から下、下から上の4パターンのCSSアニメーションを考えてみました。
実際のデモはこちら。
デモ1(CSSのみ)
See the Pen Text fading animation with simple CSS by digistate (@digistate) on CodePen.
このサンプルの大まかな構造は、まずテキストは文字色をなくし、background-image
で単色で透過していくグラデーション背景(linear-gradient
)を設定します。
background-size
でこのグラデーション背景を拡大し、background-clip: text
を指定することでテキスト部分をグラデーション背景でくり抜かれた状態にし、background-position
でグラデーション背景の位置を透過部分とテキストが重なるようにずらすことで、初期状態ではテキストが見えないようにしておきます。
最後に、animation
プロパティで background-position
にて背景の位置を戻すキーフレームを指定することで、ページ表示時にCSSアニメーションが実行されてグラデーションでくり抜かれたテキストが表示される仕組みです。
HTMLの構造
HTMLは至ってシンプル。
アニメーションさせるテキストには、fade-text
という共通セレクタを付けておきます。
さらに、アニメーションのパターン(表示方向)を決めるセレクタ(to__right
, to__left
, to__top
, to__bottom
)のいずれかを指定しておきます。
<div class="fade-text to__right">左から右へフェードインするテキスト</div>
あとはCSSでアニメーションのキーフレームを作成すれば動作しますが、アニメーション時間や各要素間のアニメーション開始の時差などをCSSで決め打ちでまとめてしまうと、汎用性が全くなくなってしまうため、CSS変数(カスタムプロパティ)を利用してインラインのstyle属性で要素ごとでアニメーション時間、表示遅延時間、イージングの種類は自由に指定できるようにしておきます。
<div class="fade-text to__right" style="--duration: 2.4s; --delay: 0.6s; --ease: ease-out"> 左から右へフェードインするテキスト </div>
上記の style="--duration: 2.4s; --delay: 0.6s; --ease: ease-out"
の部分がCSS変数です。
後述のCSS(var()
)でそれを受け取って各要素から指定された条件でアニメーションを実行します。
CSS
アニメーションさせるテキストに共通して付ける .fade-text
セレクタは以下のように定義しています。
.fade-text{ display: block; color: transparent; font-size: 30px; line-height: 1.4; margin-bottom: 40px; background-clip: text; -webkit-background-clip: text; background-size: 300% 300%; }
ポイントは、color:transparent
で文字色を透過状態にし、background-clip:text
でこの部分はテキストでくり抜きにして、background-size:300% 300%
で背景エリアを拡大しています。
次にアニメーションのパターン(表示方向)ごとのCSSをコーディングします。
例えば、テキストを左から右へフェードイン表示する場合のCSSは以下のようにしています。
.fade-text.to__right { background-image: linear-gradient(to right, #fff 30%, rgba(255, 255, 255, 0) 60%); background-position: left 100% center; transform: translate(-20px, 0); -webkit-animation: toRight var(--duration, 2.4s) var(--ease) var(--delay, 0.6s) forwards; animation: toRight var(--duration, 2.4s) var(--ease) var(--delay, 0.6s) forwards; }
この場合は、background-image: linear-gradient(to right, #fff 30%, rgba(255, 255, 255, 0) 60%)
で白のグラデーション背景にし、background-position: left 100% center
で左から100%の位置に移動させ、animation
プロパティで左から右にフェードインするキーフレームを指定しています。
animation
プロパティは、右側にフェードインするための toRight
というアニメーションキーフレーム(後述)を指定し、アニメーション時間(var(--duration)
)、イージング(var(--ease)
)、開始遅延(var(--delay)
) についてはCSS変数で要素から指定された値になるようにしています。
animation: toRight var(--duration, 2.4s) var(--ease) var(--delay, 0.6s) forwards;
animation
プロパティで指定されているキーフレームは、アニメーション終了状態のCSSをセットします。
@keyframes toRight { 100% { transform: translate(0, 0); background-position: left 0% center; } }
この要領で、さらに左から右、上から下、下から上への初期状態のCSSとキーフレームを追加すれば完成です。
デモ2(CSS + JavaScript)
デモ1ではCSSのみでフェードインテキストを表現してみましたが、ちょこっとだけ JavaScript を追加すれば、HTMLとCSSをよりすっきりさせて、各要素間のアニメーション開始遅延(順番にフェードイン)を簡単に自動化できます。
See the Pen Text fading animation with simple CSS by digistate (@digistate) on CodePen.
JavaScript の処理は、アニメーション対象となる各要素に表示用のセレクタ(.reveal
)を指定した時間おきにずらしながら追加するだけのシンプルな内容です。
// アニメーション対象要素をすべて取得 const el = document.querySelectorAll('.fade-text'); // 各要素について Array.from( el, function(e, i) { // 要素ごとに 800 ミリ秒ずらしながら setTimeout(function(){ // .reveal セレクタを要素に追加 e.classList.add( 'reveal' ); }, 600 + i * 800 ); // 800ミリ秒ずつずらしてセレクタを追加(順番に表示するため) });
デモ3(スクロールをトリガーにする)
対象のアニメーション要素がページ表示時の領域内ではなく、下方にスクロールしてはじめて表示される箇所にある場合、先述の方法ではページ表示時にアニメーションが始まってしまうため、意味がありません。
アニメーションの発火タイミングを、スクロールしてはじめて対象要素が表示エリアに入ったときにするには、ここでは現時点で最も効率がよいと思われる GSAP という JavaScript のアニメーションライブラリと、GSAP の ScrollTrigger というプラグインを利用することで、簡単に実現できます。
GSAP や ScrollTrigger については、以下の記事でとても分かりやすく解説されています。
ScrollTriggerのわかりやすい解説

GSAP は利便性が高くかつ軽量で WebGL、canvas、SVG も扱える非常に優れたライブラリですが、独自ライセンスであるため、商用利用には注意が必要です。
See the Pen Text fading animation using GSAP and ScrollTrigger by digistate (@digistate) on CodePen.
HTMLの構造
GSAP では、to()
や fromTo()
などのアニメーションの開始、終了状態をパラメータで渡すだけでアニメーションを実行してくれるメソッドがありますが、この中でアニメーションの終了状態(to()
)を各要素から受け取るために、各要素(div
)に data
属性で先述のキーフレームの内容と同じスタイルをセットしておきます。
<div class="fade-text to__right" data-to-x="0" data-to-bg-position="left 0% center"> 左から右へフェードインするテキスト </div>
上記の data-to-x="0" data-to-bg-position="left 0% center"
の部分が終了状態の transform
、background-position
の値になり、これを GSAP (JavaScript)側で受け取り、アニメーションを実行します。
同じように右から左、上から下、下から上にフェードインする要素を用意します。
JavaScriptの構造
GSAP の to()
メソッドを利用してアニメーションの終了状態をセットします。
gsap.to( elem, // 対象要素 '.fade-in' など対象要素のセレクタをテキストで指定もOK { ease: 'power1.out', // イージングのパターン duration: 2.4, // アニメーション時間(秒) autoAlpha: 0, // 非表示(opacity:0, visibility: hidden) x: 100, // 水平方向(右)への移動距離(px) -100 とすると左へ移動 y: 100, // 垂直方向(下)への移動距離(px) -100とする上へ移動 xPercent: 10, // 水平方向(右)への移動距離(%) -10 とすると左へ移動 xPercent: 10, // 垂直方向(下)への移動距離(%) -10とする上へ移動 scale: 1, // 要素の拡大率(1 : 等倍) backgroundColor: #ffffff, // 背景カラー delay: 0.6 // アニメーション開始遅延(秒) yoyo: true, // 往復リピートさせる repeat: 0, // リピート回数 -1 で無限 // アニメーション終了時のコールバック onComplete: function() { console.dir('finished'); }, } );
その他にも、CSS で指定するような形でたくさんのパラメータが利用できます。
そして、スクロールを契機としてアニメーションを実行させるための ScrollTrigger は以下のようにして利用します。
ScrollTrigger.create({ trigger: elem, // 対象要素 '.fade-in' など対象要素のセレクタをテキストで指定もOK start: 'top 80%', // 対象要素のどの位置が画面のどの位置にきたらアニメーションを実行するか onEnter: function() { animateTo(elem) }, // アニメーション(GSAP)の処理 onEnterBack: function() { animateTo(elem) }, // 再び表示されたときの処理 onLeave: function() { hide(elem) }, // 画面から見えなくなったときの処理 scrub: true, // スクロールに同期してアニメーションを行う pin: true, // アニメーション中に要素を固定 });
アニメーション要素は複数あるため、querySelectorAll
で取得したオブジェクトを配列化してループ処理し、その中で ScrollTrigger を実行します。
// .fade-text セレクタを持つ要素を取得 const el = document.querySelectorAll('.fade-text'); // 各要素について Array.from( el, function(e, i) { // ScrollTrigger を実行 ScrollTrigger.create({ trigger: e, start: 'bottom 80%' onEnter: function() { animateTo( e, i ) } }); });
アニメーションが実行される onEnter
プロパティで指定している自作の animateTo()
という関数内で、GSAP の to()
関数が実行され、実際のフェードインアニメーションが行われます。
function animateTo( e, i ){ gsap.to( e, { ease: 'power1.out', duration: 2.4, x: e.dataset.toX || 0, y: e.dataset.toY || 0, backgroundPosition: e.dataset.toBgPosition || 'center', } ); }
GSAP側では、各要素に指定されているdata属性を e.dataset.toX
、e.dataset.toY
で transform
の値を受け取り、e.dataset.toBgPosition
で終了状態の background-position
の値を受け取っています。
おわりに
CSSのみで表現するといいながら、結局GSAPまで使ってゴリゴリにJavaScriptと絡めたサンプルも紹介してしまいましたが、GSAPを利用することでスクロールによる表示にも簡単なコードのみで対応できますし、実用性もあります。
簡単に実装できそうなので、GSAPは利用しませんが、スクロールでフェードインするテキストは、提供中の DigiPress テーマ専用のブロックエディター拡張プラグイン「DigiPress Ex – Blocks」に新たなブロックとして追加したいと思います。