Оптимизация Lazy Loading для видео и 3D-графики

Я являюсь веб-разработчиком, который слишком долго закрывал глаза на проблемы с производительностью своего сайта. Пока однажды Google PageSpeed Insights не «порадовал» меня оценкой 32/100. Виновниками оказались тяжелые видео и 3D-модели, которые грузились даже тогда, когда пользователь до них не доскроллил. Так начался мой путь в мир оптимизации. Сегодня расскажу, как с помощью ленивой загрузки, Intersection Observer и кодеков нового поколения я сократил время загрузки страниц на 68% и удержал аудиторию, которая раньше уходила, не дождавшись контента.

Атрибут loading=»lazy» это только начало

Когда я впервые добавил <img loading="lazy"> для изображений, прогресс был заметен. Но с видео и WebGL-графикой всё оказалось сложнее. Оказалось, стандартный атрибут loading="lazy" для <video> работает не во всех браузерах, а 3D-модели на Three.js вообще требуют кастомных решений.

Что я сделал:

  1. Для встроенных видео использовал гибридный подход:
    html
    <video controls preload="none" loading="lazy" poster="placeholder.jpg">
      <source src="video.mp4" type="video/mp4">
    </video>

    preload="none" + loading="lazy" предотвращают загрузку до момента взаимодействия пользователя.

  2. Для 3D-графики создал систему лоадеров:
    Пока модель не в области видимости, показывал низкополигональный превью (до 50 КБ вместо 5 МБ оригинальной модели).

Ошибка, которую я допустил:
Думал, что loading="lazy" достаточно. На практике для динамически добавляемого контента (например, в бесконечной ленте) он бесполезен. Тут на помощь пришёл Intersection Observer.

Intersection Observer

Когда я узнал об Intersection Observer API, это перевернуло мое представление об оптимизации. В отличие от loading="lazy", он даёт полный контроль. Можно задавать отступы для предзагрузки, работать с любыми элементами и даже анимировать появление.

Как я интегрировал его для видео:

javascript
const videoObserver = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const video = entry.target;
      video.src = video.dataset.src;
      video.load();
      videoObserver.unobserve(video);
    }
  });
}, { rootMargin: '200px' }); // Начинаем загрузку за 200px до элемента

document.querySelectorAll('video[data-src]').forEach(video => {
  videoObserver.observe(video);
});

Теперь видео грузятся только когда до них остаётся 200px скролла, а не при загрузке страницы.

Для 3D-графики на Three.js:
Использовал аналогичный подход, но с дополнительной логикой:

  • При первом попадании в зону видимости загружаю 10% текстур.
  • При приближении (за 500px) — остальные ресурсы.
  • Если пользователь ушёл с экрана, выгружаю GLSL-шейдеры из памяти.

Как я сжал 4K-видео в 5 раз без потерь

Раньше я экспортировал видео в MP4/H.264 и удивлялся, почему файлы весят по 200 МБ. Пока не открыл для себя кодеки AV1, VP9 и HEVC:

  1. AV1 король сжатия.
    Пример из практики:

    • Исходный файл: 4K, 120 сек, 1.2 ГБ (H.264).
    • После кодирования в AV1: 230 МБ (качество CRF 32).
      Поддерживается Chrome, Firefox, Edge. Для Safari пришлось добавить fallback в HEVC.
  2. WebM + VP9 идеален для коротких роликов.
    Использую для фоновых видео-заставок:

    html
    <video autoplay muted loop>
      <source src="bg-video.webm" type="video/webm">
      <source src="bg-video.hevc.mp4" type="video/mp4">
    </video>
  3. HEVC/H.265 спасение для Apple-устройств.
    Хотя требует лицензирования, разница в размере поражает:
    H.264 (50 МБ) → HEVC (22 МБ) с тем же битрейтом.

Мой стек инструментов для конвертации:

  • FFmpeg для пакетного сжатия через скрипты.
  • HandBrake интуитивное управление пресетами.
  • Squoosh (от Google) оптимизация текстур для 3D-моделей.

Как объединить всё для максимальной скорости

Секрет в том, чтобы технологии работали вместе. Вот пример моего «рецепта» для страницы с 3D-портфолио:

  1. Первоначальная загрузка:
    • Показываем статичный SVG-плейсхолдер.
    • Загружаем аудио и критический CSS.
  2. При скролле до 1000px до секции:
    • Intersection Observer инициирует предзагрузку легковесной версии модели (формат GLB с Draco-сжатием).
  3. Когда модель в области видимости:
    • Запускаем рендеринг с низким разрешением (720p).
    • Параллельно догружаем 4K-текстуры в фоне.
  4. Если пользователь остаётся на секции >5 сек:
    • Подгружаю продвинутые шейдеры и анимации.

Результат: время полной загрузки сократилось с 11.8s до 3.4s, а отказы на мобильных устройствах упали на 40%.

Что проверить перед запуском

  1. Атрибуты <video>:
    preload="none"mutedplaysinline для мобильных.
  2. Сжатие 3D-моделей:
    • Draco Compression в Blender.
    • Оптимизация текстур через Basis Universal.
  3. Fallback для кодеков:
    Всегда включайте 3 варианта источника:

    html
    <video>
      <source src="video.av1.mp4" type="video/mp4; codecs=av01.0.05M.08">
      <source src="video.hevc.mp4" type="video/mp4; codecs=hevc">
      <source src="video.vp9.webm" type="video/webm">
    </video>
  4. Тестирование в Lighthouse:
    Особенно параметр «Largest Contentful Paint», он не должен включать видео/3D.

Оптимизация мультимедиа это комплекс из:

  1.  Ленивой загрузки через Intersection Observer.
  2. Современных кодеков вместо устаревших форматов.
  3. Прогрессивного улучшения для разных устройств.

После внедрения этих методов мой сайт стал грузиться быстрее, чем приложения большинства конкурентов. И да, Google PageSpeed теперь стабильно показывает 92-95/100.

Поделиться статьей:
Поддержать автора блога

Поддержка автора осуществляется с помощью специальной формы ниже, предоставленной сервисом «ЮMoney». Все платёжные операции выполняются на защищённой странице сервиса, что обеспечивает их корректность и полную безопасность.

Персональные рекомендации
Оставить комментарий