#52 UIアニメーション設計のアンチパターン大全|やってはいけない実装と改善方法

UI animation anti patternsのアイキャッチ画像

UIアニメーションは「動けばOK」ではありません。

  • カクつく
  • 状態が壊れる
  • 意図しない挙動になる

こういった問題の多くは、アンチパターン(悪い設計)が原因です。

この記事では、
実際によくあるミスをベースに

  • ❌ 悪い実装
  • ✅ 改善方法

の形で整理していきます。

① 状態を持たずに直接DOMを操作する

❌ よくあるコード

button.addEventListener('click', () => {
  box.style.transform = 'translateX(100px)';
});

問題点

  • 状態がどこにも存在しない
  • 複数操作で破綻する
  • アニメーション制御ができない

✅ 改善(状態を持つ)

let state = {
  x: 0,
  targetX: 0
};

button.addEventListener('click', () => {
  state.targetX = 100;
});

👉 状態管理の基本はこちら

② requestAnimationFrameを使わない

❌ setIntervalで制御

setInterval(() => {
  box.style.left = parseInt(box.style.left || 0) + 1 + 'px';
}, 16);

問題点

  • フレーム同期しない
  • カクつく
  • CPU無駄

✅ requestAnimationFrameにする

function loop() {
  state.x += (state.targetX - state.x) * 0.1;

  box.style.transform = `translateX(${state.x}px)`;

  requestAnimationFrame(loop);
}

loop();

👉 詳細解説

③ 状態と描画が混ざっている

❌ 悪い例

function update() {
  state.x += 1;
  box.style.transform = `translateX(${state.x}px)`;
}

問題点

  • テストできない
  • 再利用不可
  • バグりやすい

✅ 分離する

function update() {
  state.x += 1;
}

function render() {
  box.style.transform = `translateX(${state.x}px)`;
}

function loop() {
  update();
  render();
  requestAnimationFrame(loop);
}

👉 設計の基礎

④ easingを使わずに一定速度で動かす

❌ 機械的な動き

state.x += 2;

問題点

  • UXが悪い
  • 人間らしさがない

✅ easing / lerp

state.x += (state.targetX - state.x) * 0.1;

👉 easing解説

⑤ scrollイベントで直接処理する

❌ よくある地獄

window.addEventListener('scroll', () => {
  box.style.transform = `translateY(${window.scrollY}px)`;
});

問題点

  • 高頻度で重い
  • ガクガク
  • 制御不能

✅ stateに変換

let state = {
  scroll: 0
};

window.addEventListener('scroll', () => {
  state.scroll = window.scrollY;
});
function loop() {
  box.style.transform = `translateY(${state.scroll}px)`;
  requestAnimationFrame(loop);
}

👉 scroll設計

⑥ アニメーションを途中で止められない

❌ 典型

function animate() {
  requestAnimationFrame(animate);
}

問題点

  • 無限ループ
  • 制御不能
  • メモリ浪費

✅ フラグ管理

let isRunning = true;

function loop() {
  if (!isRunning) return;

  requestAnimationFrame(loop);
}

⑦ 複数アニメーションが干渉する

❌ 上書き地獄

box.style.transform = 'translateX(100px)';
box.style.transform = 'scale(1.2)';

問題点

  • transformが上書きされる
  • 意図しない動き

✅ 合成する

box.style.transform = `
  translateX(${state.x}px)
  scale(${state.scale})
`;

⑧ 入力イベントをそのまま使う

❌ 生のイベント

mousemove = (e) => {
  box.style.left = e.clientX + 'px';
};

問題点

  • ノイズが多い
  • カクつく
  • デバイス依存

✅ 状態化+補間

state.targetX = e.clientX;

state.x += (state.targetX - state.x) * 0.1;


🧪 実験:Anti vs Good Animation Comparison

以下のデモでは
左:アンチパターン
右:改善版
を比較できます。

まとめ

UIアニメーションの質は「設計」で決まります。

今回のポイント:

  • 状態を持つ
  • requestAnimationFrameを使う
  • update / renderを分離
  • easingを使う
  • 入力をそのまま使わない

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA