2026年5月20日

2026年5月20日

WordPressでスクロールアニメーションを実装する方法

はじめに

スクロールアニメーションは、要素がビューポートに入ったタイミングでフェードインやスライドインするエフェクトです。Intersection Observer API を使うことでパフォーマンスを確保しながら実装できます。

症状・原因

  • スクロールしたら要素がフワっと表示されるようにしたい
  • 要素が画面に入ったタイミングでアニメーションさせたい
  • スクロールイベントを使わずにパフォーマンス良く実装したい
  • 遅延アニメーションで要素を順番に表示したい

解決手順

ステップ1:CSSでアニメーション定義

/* style.css — アニメーション定義 */
@keyframes fadeInUp {
    from { opacity: 0; transform: translateY(30px); }
    to   { opacity: 1; transform: translateY(0); }
}

@keyframes fadeInLeft {
    from { opacity: 0; transform: translateX(-30px); }
    to   { opacity: 1; transform: translateX(0); }
}

@keyframes fadeIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* 初期状態(非表示) */
[data-animate] {
    opacity: 0;
}

/* アニメーション実行(Intersection Observer が付与) */
[data-animate].is-animated {
    animation-fill-mode: both;
    animation-duration: 0.6s;
    animation-timing-function: ease-out;
}

[data-animate="fade-up"].is-animated    { animation-name: fadeInUp; }
[data-animate="fade-left"].is-animated  { animation-name: fadeInLeft; }
[data-animate="fade-in"].is-animated    { animation-name: fadeIn; }

/* アニメーション遅延(順番に表示) */
[data-delay="100"].is-animated { animation-delay: 0.1s; }
[data-delay="200"].is-animated { animation-delay: 0.2s; }
[data-delay="300"].is-animated { animation-delay: 0.3s; }

/* prefers-reduced-motion 対応 */
@media (prefers-reduced-motion: reduce) {
    [data-animate] { opacity: 1; }
    [data-animate].is-animated { animation: none; }
}

ステップ2:Intersection Observer で実装

// js/scroll-animation.js
document.addEventListener('DOMContentLoaded', function() {

    const observer = new IntersectionObserver(function(entries) {
        entries.forEach(function(entry) {
            if (entry.isIntersecting) {
                entry.target.classList.add('is-animated');
                // 一度表示したら監視を停止(パフォーマンス最適化)
                observer.unobserve(entry.target);
            }
        });
    }, {
        threshold: 0.1,    // 10%見えたらトリガー
        rootMargin: '0px 0px -50px 0px'  // 画面下50px手前でトリガー
    });

    // data-animate 属性を持つ要素を全て監視
    document.querySelectorAll('[data-animate]').forEach(function(el) {
        observer.observe(el);
    });
});

ステップ3:テンプレートでの使い方

// template-parts/content.php — 記事カードにアニメーション適用
<article data-animate="fade-up" data-delay="<?= ($index % 3) * 100 ?>">
    <?php the_title('<h2>', '</h2>'); ?>
    <?php the_excerpt(); ?>
</article>
<!-- HTMLで直接使う場合 -->
<section data-animate="fade-in">
    <h2>セクション見出し</h2>
</section>

<div class="card-grid">
    <div data-animate="fade-up" data-delay="0">カード1</div>
    <div data-animate="fade-up" data-delay="100">カード2</div>
    <div data-animate="fade-up" data-delay="200">カード3</div>
</div>

ステップ4:Gutenbergブロックに自動でアニメーションを追加

// functions.php — 特定ブロックに自動でdata-animate属性を追加
add_filter('render_block', function(string $html, array $block): string {
    $animate_blocks = [
        'core/heading'  => 'fade-up',
        'core/image'    => 'fade-in',
        'core/group'    => 'fade-up',
        'core/columns'  => 'fade-up',
    ];

    if (!isset($animate_blocks[$block['blockName']])) return $html;

    $type = $animate_blocks[$block['blockName']];
    // 先頭のタグにdata-animate属性を追加
    return preg_replace('/^(<\w+)/', '$1 data-animate="' . $type . '"', $html, 1);
}, 10, 2);

ステップ5:スクリプトのエンキュー

// functions.php
add_action('wp_enqueue_scripts', function(): void {
    wp_enqueue_script(
        'scroll-animation',
        get_template_directory_uri() . '/js/scroll-animation.js',
        [],
        filemtime(get_template_directory() . '/js/scroll-animation.js'),
        true
    );
});

注意事項

  • Intersection Observer はIE11以外の全モダンブラウザで対応しています。IE11対応が必要な場合はpolyfillを使用してください
  • @media (prefers-reduced-motion: reduce) で動きを抑える設定のユーザーにはアニメーションを無効化してください。アクセシビリティ上の重要な対応です
  • アニメーション済みの要素は observer.unobserve() で監視を停止することでメモリとCPUを節約できます

まとめ

Intersection Observer の isIntersecting で要素がビューポートに入ったことを検知し、is-animated クラスを付与してCSSアニメーションを発火させます。data-animate="fade-up"data-delay="100" で種類と遅延を指定できます。prefers-reduced-motion への対応も忘れずに。

お気軽にご相談ください

お見積りへ お問い合わせへ