Приостановка/возобновление анимации 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>

Ответ 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');
});

Вышеуказанные два способа не работают в iframe CodePen, JSFiddle, JSBin и т. Д.; возможная причина предоставляется в конце сообщения. Но вот видео-ссылка, показывающая, как код работает в режиме отладки CodePen.

Живой пример

Подтверждено в:

  1. Google Chrome v70.0.3538.67 (официальная сборка) (32-разрядная версия)

  2. Firefox Quantum v62.0.3 (32-разрядная версия)

  3. Internet Explorer v11+


Возможная причина, по которой код не работает внутри iframe:

Когда я попытался получить доступ к root window (как parent объект, обратите внимание, что это не iframe window), в консоли было зарегистрировано следующее сообщение об ошибке:

enter image description here

А это означает, что я не могу получить доступ к root window CodePen и другим. Поэтому, если я не могу получить к нему доступ, я не могу добавить к нему прослушивателей событий.

Ответ 2

Для меня ваш пример работает большую часть времени.

Однако я бы использовал проценты, а также добавлял начальную точку в ключевые кадры:

@keyframes move {
  0% { 
    left: 0px;
  }
  100% {
    left: 500px
  }
}

Также обнаружение неактивной вкладки не срабатывает всегда. Неактивное окно работает лучше: (с помощью jQuery)

$(window).on("blur focus", function(e) {
    var prevType = $(this).data("prevType");

    if (prevType != e.type) {
        var element = document.getElementById("test");
        switch (e.type) {
            case "blur":
                element.style["animation-play-state"] = "paused";
                break;
            case "focus":
                element.style["animation-play-state"] = "running";
                break;
        }
    }

    $(this).data("prevType", e.type);
})

Ответ 3

Вам не нужно использовать какие-либо классы или переключать их для получения ожидаемого результата. Здесь загрузите этот gist- файл gist и попытайтесь в конце, давайте посмотрим, работает ли это.

Вам нужно установить состояние animation-play-state при написании CSS, чтобы test div paused.

После того, как окно нагрузки, установите animation-play-state для running затем установите их снова в соответствии с blur и focus события.

Также я заметил, что использование префикса браузера (-webkit-animation-play-state) помогло мне получить ожидаемый результат, поэтому обязательно используйте их. Я тестировал на firefox и chrome, отлично работает для меня.

Примечание. Это может не работать в этом фрагменте кода здесь (поскольку фрагмент не находится в главном окне этой текущей вкладки). Загрузите ссылку gist, указанную выше, и проверьте в конце.

window.onload = function() {
  // not mentioning the state at all does not provide the expected result, so you need to set 
  // the state to paused and set it to running on window load
  document.getElementById('test').style.webkitAnimationPlayState = "running";
  document.getElementById('test').style.animationPlayState = 'running';
}

window.onblur = function() {
  document.title = 'paused now';
  document.getElementById('test').style.webkitAnimationPlayState = "paused";
  document.getElementById('test').style.animationPlayState = 'paused';
  document.getElementById('test').style.background = 'pink'; // for testing
}

window.onfocus = function() {
  document.title = 'running now';
  document.getElementById('test').style.webkitAnimationPlayState = "running";
  document.getElementById('test').style.animationPlayState = 'running';
  document.getElementById('test').style.background = 'red'; // for testing
}
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;
  /* add the state here and set it to running on window load */
  -webkit-animation-play-state: paused;
  animation-play-state: paused;
}

@keyframes move {
  to {
    left: 90vw
  }
}
<div id="test"></div>