タブを切り替えるときに CSS アニメーションを一時停止/再開する 質問する

タブを切り替えるときに CSS アニメーションを一時停止/再開する 質問する

ページには長時間実行される CSS アニメーションがたくさんあります。ユーザーが別のタブに切り替えたときにはアニメーションを一時停止し、ユーザーが元のタブに戻ったときにアニメーションを再開したいと考えています。簡単にするために、現時点ではクロスブラウザ ソリューションを目指していません。Chrome で動作させるだけで十分でしょう。

document.addEventListener("visibilitychange", function() {
  if (document.hidden) {
    document.querySelector("#test").classList.add("paused");
  } else {
    document.querySelector("#test").classList.remove("paused");    
  }
});
div#test {
  width: 50px;
  height: 50px;
  background-color: red;
  position: absolute;
  left: 10vw;
  animation-name: move;
  animation-duration: 5s;
  animation-fill-mode: forwards;
  animation-timing-function: linear;
}

@keyframes move {
  to {
    left: 90vw
  }
}

.paused {
  animation-play-state: paused !important;
  -webkit-animation-play-state: paused !important;
  -moz-animation-play-state: paused !important;
}
<div id="test"></div>

上記のコードは赤い四角形を水平方向に移動します。四角形のアニメーションが完了するまでに 5 秒かかります。

問題:アニメーションが開始したら、別のブラウザ タブに切り替えます。しばらく経ってから (5 秒以上)、最初のタブに戻ります。

期待される結果:長方形は、中断した地点から経路を継続します。

実結果:ほとんどの場合、四角形は最終目的地に表示され、そこで停止します。期待どおりに動作することもあります。ビデオ問題を示します。

animation-fill-modeとにさまざまな値を試してみましたanimation-timing-functionが、結果は常に同じでした。rv7指摘したCodePen、JSFiddle、JSBin、stackoverflow JS ツールで例を共有すると結果に影響が出るため、ローカル HTTP サーバー上の静的ページに対して直接テストする (または以下のリンクを使用する) ことをお勧めします。

利便性のために展開しました上記のコードをHerokuにこのアプリは静的な Node.js HTTP サーバーであり、無料サブスクリプションで実行されるため、ページが初めて読み込まれるまでに最大 5 分かかる場合があります。このページに対するテスト結果:

失敗 Chrome 64.0.3282.167 (公式ビルド) (64 ビット) Linux Debian Stretch (PC)
失敗 Chrome 70.0.3538.67 (公式ビルド) (64 ビット) Windows 10 (PC)
失敗 Chrome 70.0.3538.77 (公式ビルド) (32 ビット) Windows 7 (PC)
失敗 Chrome 70.0.3538.77 (公式ビルド) (64 ビット) OSX 10.13.5 (Mac mini)
失敗 FF Quantum 60.2.2esr (64 ビット) Linux Debian Stretch (PC)
OK Safari 11.1.1 (13605.2.8) (Mac mini)

ページ可視性 APIfocus次のようにウィンドウとblurイベントに置き換えることができます。

window.addEventListener("focus", function() {
    document.querySelector("#test").classList.remove("paused");        
});

window.addEventListener("blur", function() {
    document.querySelector("#test").classList.add("paused");
});

ただし、この置き換えは同等ではありません。ページにIFRAMEが含まれている場合、そのコンテンツを操作するとfocusblurメインウィンドウでイベントがトリガーされます。この場合、タブ切り替えコードを実行するのは正しくありません。これは場合によってはまだオプションになる可能性があるため、テスト用にページを展開しました。ここ結果はわずかに良くなりました:

失敗 Chrome 64.0.3282.167 (公式ビルド) (64 ビット) Linux Debian Stretch (PC)
失敗 Chrome 70.0.3538.67 (公式ビルド) (64 ビット) Windows 10 (PC)
失敗 Chrome 70.0.3538.77 (公式ビルド) (32 ビット) Windows 7 (PC)
失敗 Chrome 70.0.3538.77 (公式ビルド) (64 ビット) OSX 10.13.5 (Mac mini)
OK FF Quantum 60.2.2esr (64 ビット) Linux Debian Stretch (PC)
OK Safari 11.1.1 (13605.2.8) (Mac mini)
このバージョンは、Chrome 32 ビットよりも Chrome 64 ビットで失敗する頻度が高くなります。 Chrome 32 ビットでは、約 20 回の成功した試行の後、1 回だけ失敗しました。これは、Chrome 32 ビットが古いハードウェアにインストールされているという事実に関係している可能性があります。

質問:タブを切り替えるときに CSS アニメーションを確実に一時停止/再開する方法はありますか?

ベストアンサー1

あなたはfocusおよびblurイベントそれよりもvisibilitychangeイベント前者よりもブラウザのサポートが優れているためです。

let box = document.querySelector('#test');

window.addEventListener('focus', function() {
  box.style.animationPlayState = 'paused';
});

window.addEventListener('blur', function() {
  box.style.animationPlayState = 'running';
});

あるいは、CSS クラスを使用してこれを行うこともできます。

.paused {
  animation-play-state: paused !important;
  -webkit-animation-play-state: paused !important;
  -moz-animation-play-state: paused !important;
}
let box = document.querySelector('#test');

window.addEventListener('focus', function() {
  box.classList.remove('paused');
});

window.addEventListener('blur', function() {
  box.classList.add('paused');
});

上記の2つの方法は、インラインフレームCodePen、JSFiddle、JSBinなど。考えられる理由は記事の最後に記載されています。しかし、CodePenのデバッグモードでコードがどのように動作するかを示すビデオリンクがあります。

ライブ例

確認済み:

  1. Google Chrome v70.0.3538.67 (公式ビルド) (32 ビット)

  2. Firefox Quantum v62.0.3 (32 ビット)

  3. インターネット エクスプローラー v11 以上


コードが内部で動作しない理由として考えられるものiframe:

アクセスしようとしたときroot window(別名parent物体ただし、これはiframe window)、コンソールに次のエラーが記録されました。

ここに画像の説明を入力してください

つまり、私はroot windowCodePen などの。したがって、アクセスできない場合は、イベント リスナーを追加できません。

おすすめ記事