prefers-reduced-motion完全実務ガイド 2026年版アニメーションを減らしたい人に優しいUIをCSSとJSで作る コピペで使える設計と落とし穴

Web制作の現場は今、アニメーション全盛です。 スクロールでふわっと出る、背景がゆっくり動く、カードがぬるっと浮く。 見栄えは良い。達成感もある。ついでにクライアント受けも良い。

でも、その動きが誰かにとっては「見ていられない」ことがあります。 画面酔い、めまい、集中できない、気分が悪くなる。 そしてこれは、好みの問題ではなく体の反応として起きることがある。

そこで登場するのが prefers-reduced-motion です。 これは、ユーザーがOSや端末側で「動きを減らす」設定を有効にしているかを、 ブラウザが教えてくれる仕組みです。

この記事は、学習中の人にも、実務で毎日CSSとJSを触っている人にも刺さるように、

  • prefers-reduced-motionの基本と考え方
  • CSSだけでできる現実的な対応
  • JSやライブラリ系アニメーションへの対処
  • やり過ぎて壊すパターンと直し方
  • WordPressやCMSでも事故らない導入法
  • 検証方法とチェックリスト

を、実務目線でまとめます。 読み終わるころには「動きを減らす対応」が、怖い作業ではなく、 品質を上げるいつもの作業になっているはずです。

prefers-reduced-motionとは まずは最小の理解でOK

ユーザーのOS設定をブラウザ経由で検出するメディア特性

prefers-reduced-motion は、CSSのメディア特性です。 値は主に2つです。

  • reduce: 動きを減らしてほしい
  • no-preference: 特に指定なし

ポイントは、reduceが「アニメーション全部禁止」ではないこと。 ユーザーが求めているのは、不要な動きを減らすことです。 UIの理解や操作に必須の動きまで消す必要はありません。

なぜ対応が必要か 動きは便利だが副作用もある

アニメーションは情報を伝えるのに役立ちます。 状態変化を分かりやすくしたり、視線誘導をしたり、操作の手応えを作ったり。

一方で、強いモーションや視差、急なズーム、背景の移動は、 体調に影響することがあります。 だからこそ「動きを減らしたい」設定がOS側に用意されています。 Web側もそれを尊重できるようになりました。

結論 実務でまず入れるべき基本形

最初はCSSで広く守る ただしやり過ぎない

多くのサイトで効く、最初の一手はこれです。

/* motion basic */
@media (prefers-reduced-motion: reduce) {
  html:focus-within {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
}

これで、CSSアニメーションとトランジションをほぼ無効化できます。 ポイントは durationを0ではなく1ms程度にすること。 0にすると、実装によっては「開始イベントが起きない」「完了イベントが飛ばない」など、 副作用が出るケースがあります。 1msなら、多くのケースで安全に短縮できます。

そして scroll-behavior: auto。 スムーススクロールは便利ですが、動きに弱い人には負担になる場合があります。 reduce時は止める選択が現実的です。

それでも足りない場合がある ライブラリとJSは別対応

上のCSSは、あくまでCSS由来の動きに強いです。 GSAP、Lottie、SwiperのJS制御、Canvas系の演出、WebGL、動画の自動再生などは、 別で止める必要があります。

ここから先は、実務で詰まりやすいところを順番に潰します。

OS側の設定はどうなっているのか ざっくり把握

ユーザーはどこで動きを減らすのか

ユーザーは端末側で「動きを減らす」「視差効果を減らす」「アニメーションを削除」 のような設定を有効にします。 名称や場所はOSで違いますが、意味は同じです。

実務的には「ユーザーが動きを減らす設定を選んだら、Webもそれを尊重する」 これだけ覚えておけばOKです。

CSS対応の設計 何を減らし 何を残すべきか

減らすべき動きの代表例

  • 大きな要素のズームイン、ズームアウト
  • 背景が大きく移動する視差表現
  • 画面全体が流れるような長いスムーススクロール
  • 強い回転、揺れ、バウンド
  • 強いループアニメーション

これらは「きれい」より「体への負担」が勝ちやすい領域です。

残して良い動きの考え方

reduceは、動きをゼロにしろ、ではありません。

  • クリックしたことを示す軽い色変化
  • モーダルが開いたことを示す短いフェード
  • 状態変化の理解に役立つ最小限のトランジション

こうした動きは、むしろユーザビリティを助けることがあります。 reduce時は、派手さを落として、短く、控えめに、が基本方針です。

具体例 CSSでよくある演出をreduce時に置き換える

フェードとスライドはreduce時にフェードだけにする

スライドインは視線誘導に便利ですが、移動量が大きいと負担になりやすいです。 reduce時は移動をやめてフェードだけにするのが定番です。

.card {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 300ms ease, transform 300ms ease;
}

.card.is-inview {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .card {
    transform: none;
    transition: opacity 1ms ease;
  }
}

ホバーアニメーションは短く 小さく もしくは無しにする

ホバーで浮かせる演出は多用されがちです。 reduce時は、影だけ変える、色だけ変えるなどに切り替えると優しいです。

.btn {
  transition: transform 200ms ease, box-shadow 200ms ease;
}

.btn:hover {
  transform: translateY(-2px);
}

@media (prefers-reduced-motion: reduce) {
  .btn {
    transition: box-shadow 1ms ease;
  }
  .btn:hover {
    transform: none;
  }
}

スムーススクロールはreduce時に切る

scroll-behavior: smooth は便利です。 しかしreduce時は auto に戻すのが無難です。

html {
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

JavaScript対応 matchMediaで動きを分岐する

reduceを検出する最小コード

JSでの基本はこれです。

const mq = window.matchMedia('(prefers-reduced-motion: reduce)');
const prefersReducedMotion = mq.matches;

これを使うと、GSAPなどのJSアニメーションを止めたり、 代替演出に切り替えたりできます。

設定の変更をリアルタイムに反映する

ユーザーがOS設定を途中で変えるケースもあります。 実務で丁寧にやるなら、changeイベントも見ておくと良いです。

const mq = window.matchMedia('(prefers-reduced-motion: reduce)');

function applyMotionPreference() {
  const reduce = mq.matches;
  document.documentElement.dataset.motion = reduce ? 'reduce' : 'ok';
}

applyMotionPreference();
mq.addEventListener('change', applyMotionPreference);

data属性に落としておくと、CSS側でも条件分岐しやすくなります。

GSAP Lottie Swiperなどライブラリ系の止め方の方針

方針1 reduce時は初期化しない

一番事故が少ないのは、reduce時はライブラリを初期化しないことです。 動かさないのに重い処理だけ回るのが最悪だからです。

const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

if (!reduce) {
  // GSAP or Swiper init
}

方針2 代替表現に切り替える

どうしても演出が必要なら、移動をやめてフェードにする、 パララックスをやめて固定背景にする、などの置き換えが現実的です。

重要なのは、reduce時でも情報が欠けないこと。 動きが情報を担っているなら、静的な情報で補う必要があります。

方針3 すでに動いているものは止める

すでに初期化してしまっている場合は、破棄APIがあるライブラリは破棄します。 ない場合は、requestAnimationFrameやsetIntervalを止める設計が必要になります。

実務では、初期化をまとめて管理し、reduce判定で分岐する設計が一番強いです。

やり過ぎ注意 全部止めるCSSが生む副作用

transitionを全部殺すとフォーカスリングやUIが不自然になることがある

全要素に !important でdurationを極小化するのは強力ですが、 UIによっては「意図した状態変化の見え方」まで変わることがあります。

例えば、アコーディオンの高さ変化が一瞬で終わって視認しづらい、 モーダルの開閉が唐突すぎる、などです。

解決策は2つ。

  • 全体ルールは入れつつ、重要なUIだけ例外を作る
  • 全体ではなく、アニメーション用クラスだけを対象にする

現場の規模が大きいほど、後者の設計が効きます。

理想は motion utility を作る

例えば、アニメーションを付ける要素にだけ .motion を付ける。 reduce時は .motion をまとめて落とす。 この形は運用が安定します。

/* motion utility */
.motion {
  transition: transform 300ms ease, opacity 300ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .motion {
    transition-duration: 1ms !important;
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
  }
}

WordPressやCMSでの導入 実務で事故らないコツ

記事本文とUI全体を分けて当てる

WordPressのテーマによって、.entry-content など本文領域のクラスは変わります。 まずは本文とUIを分けて考えます。

  • 本文: スムーススクロールや派手な視差は不要になりがち
  • UI: 状態変化の理解のために軽い動きが役立つことがある

つまり、全体に一発で当てるよりも、段階導入が安全です。

段階導入の例

/* 1: まずはスクロールだけ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* 2: 次にアニメとトランジションを軽量化 */
@media (prefers-reduced-motion: reduce) {
  .entry-content *,
  .entry-content *::before,
  .entry-content *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
}

本文から入れて、UI全体は様子を見る。 この順が一番トラブルが少ないです。

検証方法 机上の空論で終わらせない

Chrome DevToolsでprefers-reduced-motionをエミュレートする

現場で一番便利なのは、DevToolsでメディア特性をエミュレートする方法です。 Renderingパネルで prefers-reduced-motion: reduce を選べば、 OS設定を変えなくても挙動を確認できます。

チームでレビューする時も強いです。 再現手順が共有しやすいからです。

確認すべきチェックリスト

  • reduce時に強いモーションや視差が止まる
  • reduce時でも操作は成立する モーダルやナビが壊れない
  • スムーススクロールが止まり、ページ内移動が快適になる
  • JSアニメが動かないか、代替表現に切り替わる
  • reduceとno-preferenceの両方でレイアウトが崩れない

よくある質問 実務で迷うポイントを先回り

reduceならアニメはゼロにするべき

ゼロにする必要はありません。 不要な動きを減らすのが目的です。 操作や理解に必要な最小限の表現は残して良いです。

パララックスが売りのLPはどうする

reduce時はパララックスを止めて、静的なレイアウトに落とすのが基本です。 演出が売りでも、ユーザーの設定は最優先です。

代替として、背景固定、フェード中心、セクションの余白調整などで、 雰囲気を残す設計ができます。

動画やGIFはどう扱う

prefers-reduced-motion は主にモーション表現の話ですが、 動画の自動再生や強いループGIFも負担になることがあります。

reduce時は、自動再生をやめる、サムネイルに置き換える、 再生はユーザー操作に委ねる、などが現実的です。

関連知識 ここまで押さえると一段上の実装になる

WCAGの考え方 インタラクションで起きるモーションは止められるべき

アクセシビリティの文脈では、操作によって発生するモーションは、 ユーザーが無効化できることが望ましいとされています。

prefers-reduced-motionは、その実装を後押しする強い武器です。

prefers-reduced-motion以外のユーザー設定もある

動き以外にも、ユーザーの環境設定を拾えるメディア特性があります。 例えば、ダークモード、コントラスト、色の強制など。

まずは reduce motion を確実にし、その後に拡張していくのが現場では勝ち筋です。

実務でのおすすめ運用 仕様に1行足すだけで品質が上がる

要件定義や実装メモに、次の1行を入れてください。

reduce motion設定の端末では、視差と強いモーションを無効化し、スムーススクロールを停止する。

たったこれだけで、アニメ担当が後から慌てて直す事故が減ります。 そしてレビュー時の観点も揃います。

コピペ用 テンプレ集 現場で迷わない最終形

CSSの基本テンプレ

@media (prefers-reduced-motion: reduce) {
  html:focus-within {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
}

JSの基本テンプレ

const mq = window.matchMedia('(prefers-reduced-motion: reduce)');

function prefersReducedMotion() {
  return mq.matches;
}

function initAnimations() {
  if (prefersReducedMotion()) return;
  // init GSAP, Swiper, Lottie, etc.
}

initAnimations();
mq.addEventListener('change', () => {
  // 必要ならリロードや再初期化方針を決める
  // location.reload();
});

置き換えテンプレ スライドをフェードにする

.is-anim {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 300ms ease, transform 300ms ease;
}

.is-anim.is-in {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .is-anim {
    transform: none;
    transition: opacity 1ms ease;
  }
}

まとめ 動きを減らす対応はデザインを弱くしない 体験を強くする

prefers-reduced-motionは、アニメーションを否定する仕組みではありません。

必要な動きは残し、不要な動きは減らす。 その判断を、ユーザーの意思に合わせて切り替えられる。

これはアクセシビリティ対応であると同時に、 プロダクトの信頼を上げる品質改善でもあります。

派手さだけでは勝てない時代に、 こういう丁寧さが最後に効いてきます。

まずは、スムーススクロール停止と、アニメ短縮の基本形から。 そこから段階的に、あなたのサイトに合う最適解へ育てていきましょう。

(Visited 1 times, 1 visits today)