2026年5月20日

2026年5月20日

WordPressのSVGアニメーションを実装する方法

はじめに

SVGアニメーションはベクター形式なので拡大しても画質が劣化せず、ファイルサイズも小さく保てます。WordPressではインラインSVGに直接CSSアニメーションを適用する方法が最もシンプルで、Lottieを使えばAdobeアフターエフェクトで作成したアニメーションも再生できます。

症状・原因

  • アイコンをアニメーションさせたい
  • ローディングスピナーを自作したい
  • ヒーローセクションにSVGアニメーションを入れたい
  • Lottieアニメーションを埋め込みたい

解決手順

ステップ1:インラインSVGにCSSアニメーションを適用する

WordPressはデフォルトでSVGのアップロードを許可していません。インラインSVGはテンプレートに直接記述します。

// テンプレートに直接記述
<svg class="icon-spin" xmlns="http://www.w3.org/2000/svg"
     width="40" height="40" viewBox="0 0 24 24" aria-hidden="true">
    <circle cx="12" cy="12" r="10" fill="none"
            stroke="#2271b1" stroke-width="2" stroke-dasharray="60 20"/>
</svg>
/* ローディングスピナー */
.icon-spin {
    animation: spin 1s linear infinite;
}

@keyframes spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

/* アクセシビリティ: prefers-reduced-motion */
@media (prefers-reduced-motion: reduce) {
    .icon-spin {
        animation: none;
    }
}

ステップ2:SVGパスのストロークアニメーション

<svg class="checkmark" xmlns="http://www.w3.org/2000/svg"
     width="60" height="60" viewBox="0 0 52 52">
    <circle class="checkmark-circle" cx="26" cy="26" r="25"
            fill="none" stroke="#00a32a" stroke-width="2"/>
    <path class="checkmark-check" fill="none" stroke="#00a32a"
          stroke-width="3" d="M14.1 27.2l7.1 7.2 16.7-16.8"/>
</svg>
.checkmark-circle {
    stroke-dasharray: 166;
    stroke-dashoffset: 166;
    animation: stroke 0.6s cubic-bezier(0.65, 0, 0.45, 1) forwards;
}

.checkmark-check {
    stroke-dasharray: 48;
    stroke-dashoffset: 48;
    animation: stroke 0.3s cubic-bezier(0.65, 0, 0.45, 1) 0.6s forwards;
}

@keyframes stroke {
    to { stroke-dashoffset: 0; }
}

ステップ3:WordPressでSVGアップロードを有効化する

// functions.php
// SVGのアップロードを許可(セキュリティ注意)
add_filter('upload_mimes', function(array $mimes): array {
    $mimes['svg']  = 'image/svg+xml';
    $mimes['svgz'] = 'image/svg+xml';
    return $mimes;
});

// SVGのサニタイズ(悪意あるコードを除去)
// SVG Sanitizerライブラリの使用を強く推奨
add_filter('wp_handle_upload_prefilter', function(array $file): array {
    if ($file['type'] === 'image/svg+xml') {
        // SVG Sanitizer ライブラリでサニタイズ
        // composer require enshrined/svg-sanitize
    }
    return $file;
});

ステップ4:Lottieアニメーションを埋め込む

// functions.php
add_action('wp_enqueue_scripts', function(): void {
    wp_enqueue_script(
        'lottie',
        'https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.12.2/lottie.min.js',
        [],
        '5.12.2',
        true
    );
    wp_enqueue_script('my-lottie-init', get_template_directory_uri() . '/js/lottie-init.js',
        ['lottie'], '1.0.0', true);
});
// js/lottie-init.js
document.addEventListener('DOMContentLoaded', () => {
    document.querySelectorAll('[data-lottie]').forEach(el => {
        lottie.loadAnimation({
            container: el,
            renderer:  'svg',
            loop:      el.dataset.lottieLoop !== 'false',
            autoplay:  true,
            path:      el.dataset.lottie, // JSONファイルのURL
        });
    });
});
<!-- テンプレートで使用 -->
<div data-lottie="<?php echo get_template_directory_uri(); ?>/animations/hero.json"
     data-lottie-loop="true"
     style="width: 300px; height: 300px;"
     aria-hidden="true">
</div>

ステップ5:スクロール連動SVGアニメーション

// Intersection Observer でスクロール時にアニメーション開始
const svgs = document.querySelectorAll('.animate-on-scroll');
const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            entry.target.classList.add('is-animated');
            observer.unobserve(entry.target);
        }
    });
}, { threshold: 0.3 });

svgs.forEach(svg => observer.observe(svg));
.animate-on-scroll .checkmark-circle {
    animation-play-state: paused;
}
.animate-on-scroll.is-animated .checkmark-circle {
    animation-play-state: running;
}

注意事項

  • SVGアップロードを許可する場合、