Приостановка / возобновление CSS анимации при переключении вкладок - PullRequest
0 голосов
/ 19 октября 2018

У меня есть куча длительных 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 , , совместное использование примеров в инструментах JS CodePen, JSFiddle, JSBin и stackoverflow влияет на результаты, поэтому лучше проводить тестирование непосредственно на статической странице на локальном HTTP-сервере (или используя ссылки ниже).

Для удобства я развернул приведенный выше код для Heroku .Приложение представляет собой статический HTTP-сервер nodejs, который работает по бесплатной подписке, поэтому загрузка страницы может занять до 5 минут в первый раз.Результаты тестирования на этой странице:

FAIL Chrome 64.0.3282.167 (официальная сборка) (64-разрядная версия) Linux Debian Stretch (ПК)
FAIL Chrome 70.0.3538.67 (официальная сборка) (64-бит) Windows 10 (ПК)
FAIL Chrome 70.0.3538.77 (официальная сборка) (32-разрядная версия) Windows 7 (ПК)
FAIL Chrome 70.0.3538.77 (официальная сборка) (64-разрядная версия) OSX 10.13.5(Mac mini)
FAIL FF Quantum 60.2.2esr (64-разрядная версия) Linux Debian Stretch (ПК)
OK Safari 11.1.1 (13605.2.8) (Mac mini)

API видимости страницы можно заменить на события типа focus и blur, например:

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

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

Однако эта замена не эквивалентна.Если страница содержит IFRAME, взаимодействие с их содержимым вызовет события focus и blur в главном окне.Выполнение любого кода переключения вкладок в этом случае не является правильным.В некоторых случаях это все еще может быть вариантом, поэтому я развернул страницу для тестирования здесь .Результаты немного лучше:

FAIL Chrome 64.0.3282.167 (официальная сборка) (64-разрядная версия) Linux Debian Stretch (ПК)
FAIL Chrome 70.0.3538.67 (официальная сборка) (64-бит) Windows 10 (ПК)
FAIL Chrome 70.0.3538.77 (официальная сборка) (32-разрядная версия) Windows 7 (ПК)
FAIL Chrome 70.0.3538.77 (официальная сборка) (64-разрядная версия) OSX 10.13.5(Mac mini)
OK FF Quantum 60.2.2esr (64-разрядная версия) Linux Debian Stretch (ПК)
OK Safari 11.1.1 (13605.2.8) (Mac mini)
Эта версия чаще всего выходит из строя вChrome 64-битный, чем в Chrome 32-битный.В 32-битном Chrome я получил всего 1 ошибку после ~ 20 успешных попыток.Это может быть связано с тем, что 32-разрядная версия Chrome установлена ​​на старом оборудовании.

Вопрос: есть ли способ надежно приостанавливать / возобновлять CSS-анимацию при переключении вкладок

Ответы [ 3 ]

0 голосов
/ 21 октября 2018

Вы можете перейти с 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 +


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

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

enter image description here

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

0 голосов
/ 27 октября 2018

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

Вам нужно установить 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>
0 голосов
/ 21 октября 2018

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

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

@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);
})
...