skip to content

Search

Astro View Transitions 実装ガイド - スムーズなページ遷移の実現

8 min read

ブログの詳細ページでのちらつきを防ぎ、スムーズなページ遷移を実装するために行った全ての修正内容と仕組みを詳細に解説します。

Astro View Transitions 実装ガイド

📋 概要

このドキュメントでは、ブログの詳細ページでのちらつきを防ぎ、スムーズなページ遷移を実装するために行った全ての修正内容と仕組みを説明します。

🎯 実装目標

  • ✅ ブログ詳細ページのちらつき(FOUC)防止
  • ✅ スムーズなページ遷移(SPA風体験)
  • ✅ 記事コンテンツのみふわっとアニメーション
  • ✅ ヘッダー・フッターは遷移時に保持(消えない)

🔧 実装した修正内容

1. Astro View Transitions API の導入

ファイル: src/layouts/Base.astro

変更前:

import BaseHead from "@/components/BaseHead.astro";
// その他のimport...

変更後:

import BaseHead from "@/components/BaseHead.astro";
import { ViewTransitions } from "astro:transitions";
// その他のimport...
 
<head>
    <BaseHead articleDate={articleDate} description={description} ogImage={ogImage} title={title} />
    <ViewTransitions />
</head>

仕組み:

  • ViewTransitions コンポーネントがページ間の遷移を管理
  • ブラウザの View Transition API を使用してスムーズな遷移を実現
  • SPAライクな体験を提供

2. フォント読み込み最適化

ファイル: src/styles/global.css

変更内容:

@font-face {
  font-family: "SFProRounded";
  src: url("../assets/fonts/SF-Pro-Rounded-Regular.latin.base.ttf")
    format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap; /* 追加 */
}
/* 他のフォント定義も同様に font-display: swap; を追加 */

仕組み:

  • font-display: swap により、フォント読み込み中もフォールバックフォントで表示
  • FOUT(Flash of Unstyled Text)を防止
  • ちらつきの主要原因を解消

3. ページ遷移用CSS アニメーション

ファイル: src/styles/global.css

追加されたCSS:

/* Astro Transitions スムーズな遷移 */
@layer base {
  /* ルート要素のアニメーションを無効化してちらつき防止 */
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none;
  }
 
  /* ヘッダーとフッターは遷移時に保持 */
  #main-header {
    view-transition-name: header;
  }
 
  footer {
    view-transition-name: footer;
  }
 
  /* メインコンテンツの遷移 */
  #main {
    view-transition-name: main-content;
  }
 
  /* ヘッダーとフッターは遷移しない(保持される) */
  ::view-transition-old(header),
  ::view-transition-new(header) {
    animation: none;
  }
 
  ::view-transition-old(footer),
  ::view-transition-new(footer) {
    animation: none;
  }
 
  /* メインコンテンツ専用のアニメーション */
  ::view-transition-old(main-content),
  ::view-transition-new(main-content) {
    animation-duration: 0.4s;
    animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  }
 
  ::view-transition-old(main-content) {
    animation-name: slide-out-up;
  }
 
  ::view-transition-new(main-content) {
    animation-name: slide-in-up;
  }
 
  @keyframes slide-in-up {
    from {
      opacity: 0;
      transform: translateY(20px) scale(0.98);
    }
    to {
      opacity: 1;
      transform: translateY(0) scale(1);
    }
  }
 
  @keyframes slide-out-up {
    from {
      opacity: 1;
      transform: translateY(0) scale(1);
    }
    to {
      opacity: 0;
      transform: translateY(-20px) scale(0.98);
    }
  }
 
  /* 遷移中のローディング状態 */
  body.transitioning {
    cursor: progress;
  }
 
  body.transitioning * {
    pointer-events: none;
  }
}
 
@layer components {
  /* スムーズなホバーエフェクト */
  .transition-smooth {
    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  }
 
  /* リンクのスムーズな遷移 */
  a[data-astro-prefetch] {
    transition: color 0.2s ease-in-out;
  }
}

仕組み:

  • view-transition-name で各要素に固有の遷移名を付与
  • ヘッダー・フッターは animation: none で遷移しないように設定
  • メインコンテンツのみカスタムアニメーション(縦スライド + フェード + スケール)
  • cubic-bezier で自然なイージング効果

4. ヘッダーコンポーネントの修正

ファイル: src/components/layout/Header.astro

変更内容:

<header
    id="main-header"
    class="fixed px-4 md:px-0 left-0 z-20 flex items-center md:relative top-0 h-16 w-full bg-bgColor md:bg-transparent overflow-hidden"
    transition:persist
>

仕組み:

  • transition:persist 属性により、ページ遷移時にヘッダーが保持される
  • DOM要素が再作成されずに既存要素が維持される

5. フッターコンポーネントの修正

ファイル: src/components/layout/Footer.astro

変更内容:

<footer
    class="semibold mt-auto flex w-full flex-col items-center justify-center gap-y-2 pb-4 pt-8 text-center align-top text-accent sm:flex-row sm:justify-between sm:text-sm"
    transition:persist
>

仕組み:

  • ヘッダーと同様に transition:persist でフッターを保持

6. メインコンテンツエリアの遷移設定

ファイル: src/layouts/Base.astro

変更内容:

<main id="main" class="relative flex-grow mt-32 md:mt-[3.5rem]" transition:name="main-content">
    <slot />
</main>

仕組み:

  • transition:name="main-content" で遷移対象として明示
  • CSSアニメーションの対象になる

7. ヒーローセクションの遷移効果

ファイル: src/pages/index.astro

変更内容:

<section class="max-w-xl mx-auto relative flex items-center justify-center h-screen -mt-24" transition:animate="slide">
    <div class="w-full text-center" transition:name="hero-content">
        <!-- コンテンツ -->
        <div class="flex justify-center space-x-4 mt-4">
            <a href="/posts/" data-astro-prefetch class="...transition-smooth...">
                Read Blog
            </a>
            <a href="/notes/wake-up/" data-astro-prefetch class="...transition-smooth...">
                Wake up
            </a>
        </div>
    </div>
</section>

仕組み:

  • transition:animate="slide" で特定のアニメーション効果
  • transition:name="hero-content" でヒーローコンテンツを識別
  • data-astro-prefetch でリンクの事前読み込み

8. JavaScript による遷移イベント管理

ファイル: src/components/BaseHead.astro

追加されたスクリプト:

<script>
    // ページロード後に関連リンクをプリロード
    document.addEventListener('DOMContentLoaded', function() {
        // フォント読み込み完了の検知とちらつき防止
        document.fonts.ready.then(function() {
            document.body.classList.remove('font-loading');
        });
 
        // 画像の遅延読み込み完了時のアニメーション
        const lazyImages = document.querySelectorAll('img[loading="lazy"]');
        lazyImages.forEach(img => {
            img.onload = function() {
                this.style.opacity = '1';
            };
        });
    });
 
    // View Transitions イベントハンドリング
    document.addEventListener('astro:page-load', () => {
        console.log('Page loaded with Astro Transitions!');
    });
 
    document.addEventListener('astro:before-preparation', () => {
        document.body.classList.add('transitioning');
    });
 
    document.addEventListener('astro:after-swap', () => {
        document.body.classList.remove('transitioning');
    });
</script>

仕組み:

  • astro:page-load: ページ読み込み完了時の処理
  • astro:before-preparation: 遷移準備開始時の処理
  • astro:after-swap: DOM交換完了時の処理
  • フォント読み込み完了の検知でちらつき防止

🎨 アニメーション設計思想

1. 段階的アニメーション

  • ルート要素: アニメーションなし(即座に切り替え)
  • ヘッダー・フッター: 完全に保持(再描画なし)
  • メインコンテンツ: ふわっとしたスライドアニメーション

2. 自然な動きの実現

  • 縦移動: translateY(20px) で微妙な上下動
  • スケール変化: scale(0.98) で微細な拡大縮小
  • フェード効果: opacity で滑らかな表示切替
  • カスタムイージング: cubic-bezier(0.25, 0.46, 0.45, 0.94) で心地よい加速度

3. パフォーマンス最適化

  • 不要なアニメーションを無効化
  • GPU加速対象のプロパティのみ使用
  • 遷移中のインタラクション制御

🚀 パフォーマンス最適化

1. プリフェッチ戦略

  • data-astro-prefetch 属性でリンクの事前読み込み
  • ホバー時の自動プリロード
  • 関連ページの先読み

2. フォント最適化

  • font-display: swap でレンダリングブロック防止
  • フォント読み込み完了の検知
  • フォールバックフォントでの即座表示

3. 画像最適化

  • 遅延読み込み完了時のフェードイン
  • レイアウトシフト防止

🔍 トラブルシューティング

よくある問題と解決策

  1. ヘッダー・フッターがちらつく

    • transition:persist 属性を確認
    • CSS の animation: none 設定を確認
  2. アニメーションが動作しない

    • ViewTransitions コンポーネントの導入を確認
    • transition:name 属性の設定を確認
  3. パフォーマンスが悪い

    • 不要なアニメーションの無効化
    • プリフェッチの適切な設定

📈 実装効果

Before(実装前)

  • ❌ ページ読み込み時のちらつき
  • ❌ フォント切り替え時の表示崩れ
  • ❌ 従来のページ遷移(全体リロード)

After(実装後)

  • ✅ スムーズなSPA風ページ遷移
  • ✅ ちらつき完全防止
  • ✅ 自然で心地よいアニメーション
  • ✅ パフォーマンス最適化
  • ✅ 記事部分のみの美しい遷移

🛠️ 技術スタック

  • Astro View Transitions API: SPA風遷移
  • CSS View Transition API: ブラウザネイティブアニメーション
  • Custom CSS Animations: 独自遷移効果
  • JavaScript Event Handling: 遷移ライフサイクル管理
  • Font Loading API: フォント最適化

📝 まとめ

この実装により、ブログサイトは従来のMPA(Multi-Page Application)でありながら、SPA(Single-Page Application)のような滑らかなユーザー体験を提供できるようになりました。特に記事コンテンツの遷移が美しく、ユーザーの読書体験が大幅に向上しています。


実装日: 2025年10月9日 バージョン: 1.0