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は、アニメーションを否定する仕組みではありません。
必要な動きは残し、不要な動きは減らす。 その判断を、ユーザーの意思に合わせて切り替えられる。
これはアクセシビリティ対応であると同時に、 プロダクトの信頼を上げる品質改善でもあります。
派手さだけでは勝てない時代に、 こういう丁寧さが最後に効いてきます。
まずは、スムーススクロール停止と、アニメ短縮の基本形から。 そこから段階的に、あなたのサイトに合う最適解へ育てていきましょう。

