CSS анимация ключевых кадров в iOS Safari / Chrome / Firefox мерцает / не синхронизировано - PullRequest
0 голосов
/ 19 мая 2018

У меня есть приложение React с анимацией ключевых кадров CSS для изменения внешнего вида текста, и я динамически меняю шрифт с помощью JS, используя setState и setInterval.

Я синхронизирую анимацию ключевого кадра, чтобы начать воспроизведение одновременно с вызовом setInterval, и все отлично работает в Chrome / Safari для настольных компьютеров.В Safari / Chrome / Firefox на iOS анимация мерцает и обычно не синхронизирована.Интересно, что в Safari, если я обновлю страницу после начальной загрузки, все будет работать нормально.

Я прочитал множество веток схожих проблем здесь, но ни одно из решений не работает для меня.Я попытался добавить -webkit-backface-visibility: hidden;, body {-webkit-transform:translate3d(0,0,0);} и попытаться добавить задержку в начале анимации, чтобы компенсировать мерцание.Ничего не получалось.

Вот прямая ссылка: https://stoic -khorana-e0bd2c.netlify.com /

А вот код - это крошечное приложение, в основном простоВсплывающая страница: https://github.com/themarquisdesheric/el4d/tree/master/src

У меня есть задержка для появления 'AKA', затем еще одна задержка для изменения имени, чтобы начать.

SCSS:

.aka-container {
  .aka { 
    opacity: 0;
    animation: showAKA 400ms 750ms ease-out forwards;
  }

  .name-changer {
    animation: fade 1500ms infinite paused; 

    &.playing { animation-play-state: running; }
  }

}

@keyframes showAKA {
  20%,
  100% { opacity: 1; }
}

@keyframes fade {
  0% { opacity: 0; }
  20%,
  80% { opacity: 1; }
  100% { opacity: 0; }
}

Вот компонент React:

class NameChanger extends Component {
  state = {
    name: null,
    fontFamily: null,
    index: 0,
    playing: false
  };

  componentDidMount() {
    window.setInterval(this.changeName, 1500);
    this.setState({ playing: true });
  }

  changeFont = (index) => {
    switch (index) {
      case 0:
        return 'Sedgwick Ave Display';
      case 1:
        return 'Bangers';
      case 2:
        return 'Luckiest Guy';
      default:
        return 'Bangers';
    }
  };

  changeName = () => {
    const names = ['ol lightsy', 'eladi-da', 'el-40'];
    const { index } = this.state;
    const { changeFont } = this;

    this.setState(prevState => ({
      name: names[index],
      fontFamily: changeFont(index),
      index: (index === names.length - 1) 
        ? 0 
        : prevState.index + 1
    }));
  };

  render() {
    const { name, fontFamily, playing } = this.state;

    return (
      <span
        className={`name-changer ${playing ? 'playing' : ''}`} 
        style={{ 
          fontFamily,
          position: 'relative',
          top: (name === 'el-40') ? '.25rem' : ''
        }}
      >
        {name}
      </span>
    );
  }
}

Мне интересно, почему это хорошо работает в Chrome, но выдает ошибки на мобильных устройствах.Заранее спасибо за вашу помощь!

1 Ответ

0 голосов
/ 03 июня 2018

Оказывается, iOS приостанавливает таймеры , если считает, что страница прокручивается / масштабируется.Это верно для Safari, Chrome и Firefox на iOS.

Я решил эту проблему, отказавшись от использования setInterval и добившись того же эффекта, используя вместо этого событие animationiteration.Видимо, собственный таймер анимации соблюдается, тогда как таймеры, подобные setInterval, не соблюдаются.

class NameChanger extends Component {
  state = {
    name: null,
    fontFamily: null,
    index: 0,
    playing: false
  };

  componentDidMount() {
    const { span, changeName } = this;

    span.addEventListener('animationiteration', 
      () => changeName()
    );

    this.setState({ playing: true });
  }

  changeFont = (index) => {
    switch (index) {
      case 0:
        return 'Sedgwick Ave Display';
      case 1:
        return 'Bangers';
      case 2:
        return 'Luckiest Guy';
      default:
        return 'Bangers';
    }
  };

  changeName = () => {
    const names = ['ol lightsy', 'eladi-da', 'el-40', 'elautopilot'];
    const { index } = this.state;
    const { changeFont } = this;

    this.setState(prevState => ({
      name: names[index],
      fontFamily: changeFont(index),
      index: (index === names.length - 1) 
        ? 0 
        : prevState.index + 1
    }));
  };

  render() {
    const { name, fontFamily, playing } = this.state;

    return (
      <span
        className={`name-changer ${playing ? 'playing' : ''}`} 
        ref={span => this.span = span}
        style={{ 
          fontFamily,
          position: 'relative',
          top: (name === 'el-40') ? '.25rem' : ''
        }}
      >
        {name}
      </span>
    );
  }
}
...