Back to Portfolio
March 8, 2026

Swiperを導入した

このサイトのトップページ(tacona.net)にLatest Notesとして表示していたカードの横スクロールを改良した。
CSSの素朴なoverflow-x: scroll;で対応していて味気がなかったのでSwiperのPaginationビューによって実装しなおした。

Latest NotesのSwiperデモ

Swiperとは

swiperjs.com

モバイル環境のスワイプ操作での体験を意識したスライダーを扱うライブラリ。
2026/03時点でGitHubのStarが4万件以上ついており、メンテナンスも活発。

公式の説明からいくつか特徴を抜粋。

  • Tree-shakeable: 利用するモジュールおよびCSSを個別にimportすることで、必要なものだけをバンドルに含めることが可能
  • Mobile-friendly: モバイル利用を目的としている
  • Library Agnostic: jQueryやReactなど、特定のライブラリに依存しない
  • Mutation Observer: Swiperを利用している要素や設定の変更を監視し、更新後に再計算を行なう(Hot Module Replacementと相性が良い)

その他、無限ループ表現や自動再生、アクセシビリティサポートなど、おおよそスライドアニメーションの表現をするために必要な殆どの機能が提供されている。

動機

Swiperを使ったのは割と個人的な興味でしかなくて、大乱闘スマッシュブラザーズSPECIALのファイター詳細画面で他のファイターのページへの導線にSwiperが使われてそうだったから。
Star数が多いんだな〜とか、IndexページのLatest Notesをなんとかしたいんだよな〜とかそういうところからは始まっていない。本当にただの興味で、任天堂のゲームのWEBページ制作に関わっている人がどんな技術を使っているのかを追体験したかっただけ。

導入

インストールするのはSwiper本体のみ。

pnpm add swiper

今回使ったモジュール

  • Pagination: スライド下部に現在のページ位置を表示するモジュール
  • MouseWheel: マウスホイール(スワイプを含む)によるスライド送りをする機能を追加するモジュール

実装 (Astro Component)

公式の導入やAPIリファレンスを参考に、Astroコンポーネント向けに書き直しをして実装した成果物が以下。
※実際にデプロイしているコードをそのままコピペしているのでNoteCardとか、本筋と関係ないものが混じっている。

---
import type { CollectionEntry } from "astro:content";

import NoteCard from "@/components/card/NoteCard.astro";

// 👇 必要なスタイルの呼び出し
import "swiper/css";
import "swiper/css/pagination";

interface Props {
  notes: Array<CollectionEntry<"notes">["data"]>;
}

const { notes } = Astro.props;
---

<div>
  <!-- Swiperのコンテナ -->
  <div class="swiper w-full">
    <div class="swiper-wrapper">
      <!-- スライド要素(再帰的に描画) -->
      {
        notes.map((note) => (
          <div class="swiper-slide item">
            <NoteCard note={note} />
          </div>
        ))
      }
    </div>
  </div>
  <!-- ページネーション -->
  <div class="swiper-pagination pagination"></div>
</div>

<style>
  .item {
    width: 100%;
  }
  @media (width >=48rem) {
    .item {
      width: 360px;
    }
  }

  .pagination {
    position: static;
  }
</style>

<script>
  import Swiper from "swiper";
  import { Pagination, Mousewheel } from "swiper/modules";
  import type { SwiperOptions } from "swiper/types";

  const options: SwiperOptions = {
    modules: [Pagination, Mousewheel],
    slidesPerView: 1,
    spaceBetween: 30,
    pagination: {
      el: ".swiper-pagination",
    },
    mousewheel: {
      enabled: true,
      forceToAxis: true,
      sensitivity: 0.7,
      thresholdDelta: 10,
    },
    loop: true,
    breakpoints: {
      768: {
        slidesPerView: "auto",
      },
    },
  };

  const swiper = new Swiper(".swiper", options);
</script>

基本設定

参考: Parameters

const options: SwiperOptions = {
  modules: [Pagination, Mousewheel],
  slidesPerView: 1,
  spaceBetween: 30,
  loop: true,
  breakpoints: {
    768: {
      slidesPerView: 'auto',
    },
  },
};
  • modules: 追加したいモジュールを設定する場所
  • slidePerView: 表示領域に描画するスライドの数
  • spaceBetween: スライド間の余白
  • loop: 末端のアイテムに移動した際、次のスワイプで最初のアイテムに戻るかどうか
  • breakpoints: viewport widthの状況によってオプションを変更する場合の定義

breakpointsについては、今回の場合は>= 768pxであれば表示領域に表示するスライドの数を特に指定しない(表示できる分だけする)ようにしている。

Pagination設定

参考: Pagination Parameters

const options: SwiperOptions = {
  pagination: {
    el: '.swiper-pagination',
  },
};
  • el: ページネーションのコンテンツを描画する要素のセレクタを指定

clickableをtrueにすることでページネーション部分のクリックでスライド移動などもできるか今回は特に指定していない。

MouseWheel設定

参考: MouseWheel Control Parameters

const options: SwiperOptions = {
  mousewheel: {
    enabled: true,
    forceToAxis: true,
    sensitivity: 0.7,
    thresholdDelta: 10,
  },
};
  • enabled: マウスホイールでのスライド移動の有効化
  • forceToAxis: スライドの方向に合致するホイールイベントの場合のみスライド移動を実行するかどうか
  • sensitivity: ホイールの感度
  • thresholdDelta: ホイールイベントとして扱う最小のスクロール量

forceToAxisはスライドがX軸方向なのにY軸方向のスクロールでスライド移動が発生するみたいなことを防いでいる。
sensitivitythresholdDeltaは誤操作(ちょっと触れただけでスライド移動を実行してしまう)を防ぐために調整として入れている。

Paginationスタイルの上書き

ページネーションのスタイルは変数によってテーマ管理されているので、それを上書きする。

:root {
  --swiper-pagination-color: #000000;
  --swiper-pagination-bullet-inactive-color: #ffffff;
}

--swiper-pagination-colorは現在位置の色指定、--swiper-pagination-bullet-inactive-colorはそれ以外の非アクティブな位置の色指定となる。
ここらへん、テーマの上書きの方法に関して公式ドキュメントを探せなかった。ただ、Chrome Dev Toolsで何の変数が適用されているかを確認すればどの変数を上書きすればいいかは確認できる。

やらない方がいいなと思ったこと

.swiper.swiper-wrapper.swiper-slideなどの各クラスはSwiperによって提供されているユーティリティクラスのため、このクラスに対するスタイルのオーバーライドはやめた方がいい。

/* 🙅‍♀️ 多分やめたほうが無難 */
.swiper {
  width: 100%;
}
.swiper-wrapper {
  display: flex;
  gap: 1rem;
}

別に禁止ではないと思うけど、複数箇所でSwiperを用いたスライダーを実装する場合に意図せず他の実装のスタイルに影響を出したりしやすい。
先の実装では.swiper-slideと同時に.itemというクラスを付与し、それに対してwidthを指定している。


ほとんどの挙動をSwiperOptionsの設定の調整で実現できていて、すごく使いやすいインタフェースという感じだった。
Cube EffectとかParallaxとか、結構面白い使い方ができそうなモジュールも提供されているのでいつか試してみたい。