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

Это негативно сказывалось на пользовательском опыте, и в какой-то момент разработчики браузеров решили, что хватит это терпеть.

В результате появилась Autoplay Policy 

Как понятно из названия, это политика автовоспроизведения видео в браузере. Инициатором её введения стал Chrome (с v.66), и на текущий момент эту политику поддержали все современные браузеры.

Итак, давайте поговорим, что это такое и какие палки и колёса мы можем встретить.

По сути, Autoplay Policy ограничивает автовоспроизведение видео со звуком, но не всегда. Есть ряд условий, при выполнении одного из которых браузер всё же разрешает воспроизвести видео со звуком, а именно:

  1. Пользователь взаимодействует с доменом. Это может быть клик, например по кнопке “Play”.

  2. Индекс вовлечённости домена, на котором располагается приложение, превышает пороговое значение.

  3. Пользователь добавляет веб-приложение на главный экран (в случае с PWA).

Итак, воспроизводить видео со звуком всё же можно, но если пользователь совершил какое-то действие в приложении. Или решение о воспроизведении будет принято на основании какого-то индекса вовлечённости. Что это такое?

Превышение порога индекса вовлечённости означает, что:

  1. Пользователь ранее смотрел видео на этом домене со звуком (чем больше, тем лучше).

  2. Продолжительность просмотра пользователем видео превышает n секунд (для Chrome n = 7).

  3. Вкладка открыта в момент попытки воспроизведения.

  4. Видео достаточно большое по размеру (для Chrome — от 200×140px).

Это понятно, но «Что, если?..». И когда я говорю «Что, если?..», я имею ввиду не эту особу:

и даже не этого парня с громом и молниями:

А что, если нам нужно реализовать веб-приложение с лентой видео? И лента бесконечная, видео в ней воспроизводятся автоматически при свайпе пользователя. Такое поведение очень похоже на поведение привычных нам приложений социальных сетей. И вот тут как раз появляются те самые палки и колёса, на которых работает наша лента.

Обычно базовой реализацией является что-то типа:

tryPlay() {
  // метод play возвращает promise
  this.video.play()
    .then(() => {
    	// скрываем кнопку плей, видео удалось воспроизвести
    })
    .catch(() => {
      // не удалось воспроизвести видео

      const retry = !this.video.muted;

      // выключаем звук
      this.video.muted = true;
      this.video.volume = 0;

      // пробуем воспроизвести еще раз
      retry && this.tryPlay();
    });
}

Если внимательно посмотреть на пример реализации, можно заметить, что даже без звука видео может не запуститься. Да, такой сценарий возможен, но об этом позже.

Автоплей не пройдёт

Итак, давайте подумаем, как можно реализовать ленту в условиях Autoplay Policy. Что у нас есть?

  1. n карточек с видео (дальше будем называть их постами).

  2. Видео в каждом посте нужно воспроизводить со звуком при отображении поста на экране.

Одно из отличий от реализации, представленной выше, — отсутствие необходимости запускать видео без звука. Поэтому можно сократить базовую реализацию до такой:

tryPlay() {
  // метод play возвращает promise
  this.video.play()
    .then(() => {
    	// скрываем кнопку плей, видео удалось воспроизвести
    })
    .catch(() => {});
}

Обратите внимание, что лучше не опускать вызов catch, потому что Firefox может выбросить исключение при попытке воспроизведения видео без переданного обработчика ошибок.

С этим вроде бы разобрались. Первым ограничением кажется, что видео нужно воспроизводить при действии пользователя. Это просто: просим пользователя при открытии ленты один раз совершить это действие. Например, показываем ему большую кнопку “Play”.

После того как пользователь нажмёт на эту кнопку… Внимание!

Видео воспроизвелось со звуком. И мы радостно реализовываем всю остальную логику, делаем красивый UI, Pixel Perfect по макету, любезно предоставленному талантливыми дизайнерами, прикручиваем свайп к следующим постам. И вроде бы всё классно, но… Решаем проверить свою реализацию на разных устройствах и браузерах. Берём среднестатистический смартфон, воспроизводим первое видео, свайпаем к следующему посту — и… Тадам!

Видео не воспроизвелось. 

Подключаем шнур к устройству, открываем отладчик — и видим, что браузер такой:

«Слушай, а ты же совершил действие с другим <video />, так не пойдёт, давай ты на этом его повторишь».

Выхода нет?

Что же с этим можно сделать? Ведь постов у нас много, и хотелось бы сохранить привычное для пользователя поведение. Выходов на самом деле несколько. 

Пользовательский опыт? Не, не слышал

Можно пожертвовать пользовательским опытом (что не хорошо) — и на каждом неуспешно воспроизведённом посте рисовать кнопку “Play” и надеяться, что пользователь не забьёт и посмотрит больше двух-трёх видео в ленте. 

Спасти UX полностью (ну почти)

На мой взгляд, есть лучшее решение, которое позволит частично сохранить пользовательский опыт.

Итак, мы знаем: чтобы автоматически воспроизвести видео со звуком, нам требуются как минимум одно действие пользователя и один тег <video />. Но нам никто не запрещал воспроизводить в рамках этого <video /> разные ролики, меняя src как нам вздумается.

Всё, что нам нужно, — это вынести <video /> из поста, сделать его уникальным на странице и при изменении видимости поста делать что-то типа этого:

changeVideoSrc(src: string) {
  this.video.src = '';
  this.video.load();

  setTimeout(() => {
  	this.video.src = src;
  }, 50);
}

Перед тем как изменить src у video, для некоторых браузеров (например Safari и браузеры под iOS), сначала нужно:

  1. Сбросить текущее видео.

  2. Вызвать метод load, чтобы остановить загрузку текущего видео и сбросить то, что уже загружено.

  3. С небольшой задержкой заменить видео на новое (задержка нужна, чтобы браузер успел сбросить метаинформацию).

В результате всех этих манипуляций мы увидим, что видео стали меняться при свайпе пользователя, не теряя состояние автоплея со звуком.

Но это позволит лишь частично сохранить пользовательский опыт. В чём же нюанс? Так как тег <video /> у нас теперь один на странице, то при свайпе постов нам нужно дать пользователю понять, что видео свайпается за его действием. Это позволит дать пользователю ощущение реального перемещения поста. Создать ещё один тег <video /> мы не можем, потому что в этом случае потеряем автоплей. Но так ли нам нужно свайпать в посте именно видео? Наверное, если пользователь решил смахнуть текущий пост, то этот контент ему уже неинтересен. Поэтому в базовом варианте можно сделать такое допущение — и в ответ на касание пользователя рисовать в посте обложку, например с первым кадром из видео.

Можно прийти к выводу, что задача решена — с неплохо сохранённым пользовательским опытом.

И да, я в самом начале упоминал сценарий, когда браузер не разрешит автоплей видео даже без звука. Такое поведение свойственно iOS в режиме энергосбережения. В этом режиме браузер обязательно потребует действия пользователя — без него воспроизвести видео не получится.

Преисполниться в автоплей можно с помощью этой доки.

Комментарии (13)


  1. TheRaven
    30.08.2022 17:51
    -5

    Т.е. вы нашли баг в реализации защиты от автовоспроизведения (перезагрузка видео в ранее кликнутом контейнере не сбрасывает состояние «кликнутости») и начали его эксплуатировать на своём сайте?
    Или я о вас плохо думаю, а статья про то, как вы нашли баг, написали демонстратор и сдали его разработчикам браузеров?


    1. ThisIsMaksim Автор
      30.08.2022 18:02
      +6

      Ну это не баг, это поведение не противоречащее политике автоплея, оно свойственно всем браузерам


  1. SuperTEHb
    31.08.2022 11:14
    +1

    Хуже, когда нужное тебе видео начинает автоматически воспроизводиться без звука, а ты начинаешь поиск регулировки громкости в данном конкретном плеере. Пока найдёшь пройдёт уже несколько секунд и приходится перематывать на начало. Как по мне, то пусть уж лучше стоит ждёт пока я на него тыкну.


    1. ThisIsMaksim Автор
      31.08.2022 14:57

      Согласен, но ваш сценарий больше актуален для сервисов видеохостингов, онлайн кинотеатров и т.д. В нашем сценарии, пользователи обычно целенаправленно листают ленту, ожидая следующие видео со звуков


      1. TheRaven
        31.08.2022 15:17
        -1

        Явное всегда лучше неявного: пока пользователь не выразил явного желания запустить конкретное видео — воспроизводить его не следует.
        Даже в ленте т.к. на одно просмотренное видео будет десяток пропущенных, которые зачем-то сами запустились, напугали громким звуком (мы же о тиктокподобной смотрелке говорим, а контент там соответствующий), сожрали трафик и батарею.


    1. Gordon01
      31.08.2022 15:05

      Хуже всего то что мы снова пришли к самодельным флеш плеерам, а не унифицированным браузерным (хотя они есть).


      1. ThisIsMaksim Автор
        31.08.2022 15:21

        к сожалению браузеры в большинстве случаев не поддерживают hls или dash технологию, а без них реализовывать воспроизведение больших или live видео, такое себе


  1. mogaika
    31.08.2022 13:47
    +2

    Интересно, может кто знает, в хроме для "правильных" сайтов есть исключения?


    1. ThisIsMaksim Автор
      31.08.2022 14:25
      +1

      можно вот так посмотреть about://media-engagement
      это индекс вовлеченности для вас в вашем chrome
      по идеи там могут быть преддобавлены "правильные" сайты, но я не проверял на чистом браузере


    1. amiznikov
      01.09.2022 14:36
      +1

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


      1. ThisIsMaksim Автор
        01.09.2022 14:37

        там скорее всего по умолчанию стоит индекс вовлеченности большой, потому что он точно меняется. Сравнил на двух ноутах, на одном индекс был 0.9, на втором 0.5


        1. amiznikov
          01.09.2022 14:41

          простите, а вы где посмотрели? я проверил и он у меня пуст в госте(я про хром)


          1. ThisIsMaksim Автор
            01.09.2022 21:14

            Вот тут about://media-engagement