2026年6月2日
2026年6月2日
WordPressでスクロールアニメーションを実装する方法(Intersection Observer・子テーマ)
スクロールして画面に入った要素を、少し下から浮かび上がるように表示する「スクロールアニメーション」は、プラグインを使わなくても、子テーマに JavaScript と CSS を1つずつ追加するだけで実装できます。この記事では、ブラウザ標準の Intersection Observer を使った実装手順と、表示や使いやすさを損なわないための注意点を説明します。
最初に誤解されやすい点を整理しておきます。スクロールアニメーションは見た目の演出であり、ページの読み込みを速くする効果はありません。作り方によっては、最初の画面に表示される見出しや画像を隠してしまい、表示が遅く見えたり、Core Web Vitals の LCP(最大のコンテンツが表示されるまでの時間)が悪化したりします。この記事のコードは、最初から画面内にある要素は隠さないようにしています。
仕組み
- アニメーションさせたい要素に
scroll-animationというクラスを付けます。 - JavaScript が Intersection Observer でその要素を監視します。ページを開いた時点で画面外にある要素だけに
is-waitingクラスを付けて隠します。 - スクロールして要素が画面に入ったら
is-waitingを外し、CSS のトランジションで表示します。
Intersection Observer は、要素が画面(ビューポート)に入ったかどうかをブラウザが通知してくれる仕組みです。scroll イベントで位置を毎回計算する方法と違い、スクロールのたびに処理を走らせずに済みます。また、監視を始めた直後にも1回通知が来るので、ページを開いた時点で画面内にある要素も正しく判定できます。
JavaScript が読み込まれなかった場合や、Intersection Observer に対応していないブラウザでは、要素は最初から表示されたままになります。隠すのは JavaScript が動いたときだけなので、内容が見えなくなることはありません。
手順1:子テーマにファイルを置く
テーマを直接編集すると、テーマの更新で変更が消えます。子テーマを用意し(作り方は WordPressの子テーマの作り方)、次のようにファイルを置きます。
子テーマのフォルダー/
├── functions.php
├── css/
│ └── scroll-animation.css
└── js/
└── scroll-animation.js
手順2:functions.php で読み込む
子テーマの functions.php に次のコードを追加します。子テーマのファイルを指すので、get_template_directory_uri()(親テーマ)ではなく get_stylesheet_directory_uri() を使います。
<?php
// スクロールアニメーション用の CSS と JavaScript を読み込む
add_action( 'wp_enqueue_scripts', function () {
$dir = get_stylesheet_directory();
$uri = get_stylesheet_directory_uri();
wp_enqueue_style(
'scroll-animation',
$uri . '/css/scroll-animation.css',
array(),
filemtime( $dir . '/css/scroll-animation.css' )
);
wp_enqueue_script(
'scroll-animation',
$uri . '/js/scroll-animation.js',
array(),
filemtime( $dir . '/js/scroll-animation.js' ),
array(
'strategy' => 'defer',
'in_footer' => true,
)
);
} );
- バージョン番号に
filemtime()(ファイルの更新日時)を使うと、ファイルを書き換えたときにブラウザのキャッシュが自動で更新されます。 - 第5引数の
strategyでdeferを指定すると、スクリプトがページの表示を妨げません。この配列形式は WordPress 6.3 以降で使えます。
functions.php がすでに <?php で始まっている場合は、2行目以降だけを追記します。読み込みの仕組みは wp_enqueue_scriptsでCSSとJavaScriptを読み込む方法 も参照してください。
手順3:JavaScript を作る
js/scroll-animation.js に次の内容を保存します。
// 画面外にある .scroll-animation だけを隠し、画面に入ったら表示する。
( function () {
var targets = document.querySelectorAll( '.scroll-animation' );
if ( ! targets.length || ! ( 'IntersectionObserver' in window ) ) {
return; // 対応していないブラウザでは何もしない(要素は最初から表示されたまま)
}
if ( window.matchMedia( '(prefers-reduced-motion: reduce)' ).matches ) {
return; // 動きを減らす設定の利用者にはアニメーションしない
}
var checked = new WeakSet();
var observer = new IntersectionObserver( function ( entries ) {
entries.forEach( function ( entry ) {
var el = entry.target;
if ( entry.isIntersecting ) {
// 画面に入った(または最初から画面内にある)要素は表示して監視をやめる
el.classList.remove( 'is-waiting' );
observer.unobserve( el );
} else if ( ! checked.has( el ) ) {
// 最初の判定で画面外だった要素だけを隠す
el.classList.add( 'is-waiting' );
}
checked.add( el );
} );
} );
targets.forEach( function ( el ) {
observer.observe( el );
} );
} )();
ポイントは次のとおりです。
- 最初の判定:
observe()の直後に来る最初の通知で、画面内にある要素はそのまま表示し、画面外の要素だけを隠します。一部だけ見えている要素も「画面内」として扱われ、隠されません。 - 一度表示したら監視をやめる:
unobserve()で監視を外すので、上に戻っても再びアニメーションはしません。 - 動きを減らす設定:OS やブラウザで「視差効果を減らす」「アニメーションを減らす」などを有効にしている利用者には、
prefers-reduced-motionを見てアニメーションを行いません。
手順4:CSS を作る
css/scroll-animation.css に次の内容を保存します。
.scroll-animation {
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
}
.scroll-animation.is-waiting {
opacity: 0;
transform: translateY(24px);
}
@media (prefers-reduced-motion: reduce) {
.scroll-animation {
transition: none;
}
}
/* 印刷するときは、まだ表示していない要素も見えるようにする */
@media print {
.scroll-animation.is-waiting {
opacity: 1;
transform: none;
}
}
動かすのは opacity(透明度)と transform(位置)だけにしています。この2つはブラウザが軽く処理でき、周りの要素の配置も動かさないため、レイアウトのずれ(CLS)の原因になりません。margin や top を変えるアニメーションは、周りの要素まで動くので避けます。
手順5:要素にクラスを付ける
ブロックエディターでは、アニメーションさせたいブロックを選び、右側の設定サイドバーの「ブロック」タブで「高度な設定」を開き、「追加 CSS クラス」に scroll-animation と入力します。グループブロックに付ければ、中の見出しや段落がまとめて表示されます。
テーマのテンプレートやカスタム HTML ブロックで書く場合は、次のようにクラスを付けます。
<section class="feature scroll-animation">
<h2>見出し</h2>
<p>本文</p>
</section>
ページを開き、下にスクロールして要素が浮かび上がれば完成です。キャッシュプラグインを使っている場合は、キャッシュを削除してから確認します。
使うときの注意
- 最初の画面の要素には付けない:ヘッダー直下の見出しやメイン画像は、この記事のコードなら隠されませんが、別の方法(CSS だけで最初から
opacity: 0にするなど)で実装すると表示が遅れて見えます。演出が必要なのは、スクロールして初めて見える要素だけです。 - 付けすぎない:段落ごとに動くと読みにくくなります。セクションやカード単位など、まとまりごとに付けます。
- 表示されない要素がないか確かめる:ページ内リンクで途中に移動したときや、印刷プレビューでも内容が見えるかを確認します(上の CSS では印刷時に表示するようにしています)。
- プラグインとの重複:ページビルダーやアニメーション系プラグインにも同様の機能があります。同じ要素に両方を設定すると動きがおかしくなるので、どちらか一方にします。
CSS アニメーションと Intersection Observer の組み合わせ方は CSSアニメーションとIntersection Observerで要素を表示する方法 でも説明しています。
まとめ
- スクロールアニメーションは演出であり、読み込みを速くするものではありません。最初の画面の要素は隠さないようにします。
- 子テーマに JavaScript と CSS を置き、
functions.phpでget_stylesheet_directory_uri()とdeferを指定して読み込みます。 - Intersection Observer を使い、最初の判定で画面外だった要素だけを隠し、画面に入ったら表示します。
- 動かすのは
opacityとtransformだけにし、prefers-reduced-motionで動きを減らしたい利用者に配慮します。 - ブロックエディターでは「高度な設定」の「追加 CSS クラス」で
scroll-animationを付けます。