- PVSM.RU - https://www.pvsm.ru -
Продуктовые сайты любят анимацию «крутишь колесо мыши — объект меняется на глазах». Первый инстинкт: сделать это видео с currentTime. Вот почему это почти всегда неправильный первый инстинкт, и что вместо этого используют на практике.
Эффект знаком почти всем: скроллишь страницу, и товар на экране поворачивается, открывается, меняет состояние, будто это видео, которым управляет колесо мыши. Реализовать это «в лоб» пытаются почти всегда одинаково: берут файл видео и дёргают video.currentTime от scroll‑позиции. Через пару дней разработки выясняется, почему так почти никто не делает всерьёз.
Дело не во вкусе. У формата видео для этой конкретной задачи есть три структурных ограничения:
Seek — не мгновенная операция. Декодер восстанавливает кадр от ближайшего keyframe вперёд, а не читает произвольный кадр напрямую. Скролл генерирует десятки programmatic seek‑вызовов в секунду быстрее, чем большинство декодеров успевают отработать чисто, и разные браузеры в этот момент ведут себя по‑разному: где‑то кадры «проглатываются», где‑то seek тихо схлопывается с предыдущим.
Нет надёжной прозрачности. Если объект нужно вырезать и наложить на остальной контент страницы видео с альфа‑каналом до сих пор плохо и не универсально поддерживается кросс‑браузерно, а PNG/WebP с альфой работают из коробки везде.
Мобильные ограничения на автовоспроизведение и фоновый decode добавляют ещё один слой условий, которого просто нет у обычной картинки.
Поэтому для покадрового reveal индустрия чаще уходит от видео к последовательности изображений на canvas — распространённый в дев‑сообществе паттерн для product‑страниц, хотя внутреннюю реализацию конкретных чужих сайтов я не проверял и не выдаю это за факт о какой‑то одной компании.
Стоит сравнить не «видео vs картинки», а весь спектр — у каждого подхода свой набор компромиссов.
|
Технология |
Точность скраба |
Альфа |
Вес |
Браузеры |
Годится для |
|---|---|---|---|---|---|
|
Video + currentTime |
Низкая зависит от keyframe |
нет |
отличный |
Везде, но seek ведёт себя по‑разному |
Простой ролик без построчного скраба |
|
Image sequence (canvas) |
Высокая кадр = индекс массива |
да |
Плохой без оптимизации |
Везде |
Продуктовый reveal, вырезанный объект |
|
Спрайт + CSS steps() + scroll‑timeline |
Высокая |
да |
Средний один спрайт‑лист |
Chrome/Edge/Safari — да, стабильный Firefox ещё нет (только Nightly) |
Короткие анимации без единой строчки JS |
|
WebGL / вектор (Lottie, three.js) |
Высокая, интерполяция нативна |
да |
отличный векторные данные |
Хорошая |
Иллюстративный контент, не фото |
|
WebCodecs (ручной decode) |
Высокая — полный контроль над кадром |
почти нет зависит от кодека источника |
отличный сжатие видео |
Chrome, Edge, десктоп Firefox и Safari — кроме Firefox для Android |
Уже практично кросс‑браузерно, с фоллбэком под мобильный Firefox |
Строка выделена — то, что использовали в описанном ниже случае. Не потому, что остальное хуже в принципе, а потому, что она лучше всего закрывала именно наши условия: фото‑контент, нужна альфа, нужна широкая браузерная поддержка.
Базовая идея простая: позиция скролла — это просто индекс в массиве кадров, а не таймкод видео.
Как только заменяешь видео на кадры, вылезает обратная сторона: 700+ отдельных изображений в высоком качестве весят на порядок больше, чем сжатое видео той же длительности. На одном из наших проектов исходная image‑sequence анимация тянула на посещение 23 МБ — при заметном трафике это быстро упирается в лимиты бюджетного . Комбинация из трёх приёмов ужала её до 2.4 МБ без визуальной потери самой анимации.
755 → 77 кадров в секвенции · 23 → 2.4 МБ вес на посещение · ×9.6 сокращение трафика
1. Прореживание + альфа‑бленд вместо жёсткого переключения
Оставляем не каждый кадр, а каждый N‑й — и вместо резкой смены кадра при скролле кросс‑фейдим два соседних через альфа‑канал canvas.
Первая попытка — каждый 16-й кадр — визуально сломалась: между слишком далёкими друг от друга кадрами блендинг давал не плавный переход, а «двойную экспозицию», два полупрозрачных состояния объекта одновременно. Откатились до каждого 10-го — разница между соседними кадрами оказалась достаточно маленькой, чтобы бленд читался как движение, а не наложение.
2. Порядок загрузки — не по порядку
Вместо линейной загрузки «кадр 1, 2, 3…» — сначала первый и последний кадр (задают крайние состояния), затем середина, затем середины половин, и так рекурсивно. Тот же принцип, что в конфигураторах товаров: грубый, но рабочий скраб становится доступен почти мгновенно, а детализация уточняется по мере догрузки остальных кадров.
3. Motion blur маскирует то, что осталось от прореживания
Финальный слой — не про вес файлов, а про восприятие: направленный CSS‑блюр, интенсивность которого привязана к скорости скролла в моменте. При быстрой прокрутке лёгкая смазанность — это ожидаемо и естественно глазу, поэтому она бесплатно маскирует то, что кадров под капотом физически меньше, чем при честных 60 fps. При остановке скролла блюр обнуляется, и последний кадр всегда чёткий.
Объясните «почему не видео» в первом экране статьи, а не как сноску — иначе именно это станет первым вопросом в комментариях.
Найдите порог прореживания экспериментально, не берите число из чужой статьи — предел зависит от того, насколько объект меняется между соседними исходными кадрами.
Проверьте память, а не только сеть — держать все 77 кадров как раскодированные bitmap в памяти на слабом мобильном устройстве может стоить дороже, чем сама загрузка по сети.
Заложите деградацию для слабых устройств — на медленном соединении или слабом железе честнее показать статичный кадр или сильно урезанную секвенцию, чем рваный скраб.
Автор: wojtech
Источник [3]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/canvas-2/456459
Ссылки в тексте:
[1] хостинга: https://www.reg.ru/?rlink=reflink-717
[2] Мозг: http://www.braintools.ru
[3] Источник: https://habr.com/ru/articles/1069560/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1069560
Нажмите здесь для печати.