Оптимизация доставки медиафайлов: изображения и видео 2026

Медиафайлы — это то, что убивает скорость большинства сайтов. Я видел интернет-магазины с 8-секундной загрузкой, где 90% времени уходило именно на картинки и видео, и после грамотной оптимизации они улетали до 1.8 секунд — без смены хостинга, без переписывания кода.

Почему медиафайлы убивают скорость сайта

У меня был клиент — небольшой интернет-магазин мебели на WordPress. PageSpeed показывал 23 из 100 на мобильных. Я открыл вкладку Network в DevTools и увидел картину: 47 запросов к изображениям, средний вес картинки — 1.2 МБ, никакого WebP, никакого lazy loading. Суммарный вес страницы — 38 МБ. Это катастрофа.

Грубо говоря, большинство владельцев сайтов не думают о медиафайлах вообще. Фотограф присылает RAW-конвертированные JPEG по 4-6 МБ, контент-менеджер загружает их напрямую в CMS, и всё это летит пользователю в браузер без какой-либо обработки. На десктопе с хорошим интернетом это ещё терпимо. На мобильном с LTE — уже нет. На 3G — сайт просто не загружается.

По данным HTTP Archive за 2025 год, изображения составляют в среднем 53% от общего веса страницы. Видео, если оно встроено напрямую, может добавить ещё 30-40%. И при этом большинство этих данных передаётся неэффективно: без современных форматов, без правильных заголовков кеширования, без CDN. Это деньги на ветер — и пользователи, которые уходят, не дождавшись загрузки.

Современные форматы изображений: WebP, AVIF, JPEG XL

Честно говоря, ещё три года назад я сам не особо заморачивался с WebP. Казалось — ну формат и формат, конвертировать лишний раз, зачем? Потом один проект расставил всё по местам: после перевода всех изображений на WebP вес страниц упал на 35%, а PageSpeed вырос с 61 до 84. Теперь WebP — это минимальный стандарт для любого нового проекта.

Но в 2026 году WebP — это уже не передовой край. AVIF поддерживается всеми современными браузерами (Chrome 85+, Firefox 93+, Safari 16+) и даёт на 20-50% лучшее сжатие по сравнению с WebP при том же визуальном качестве. Я перевёл несколько проектов на AVIF и в среднем получаю экономию 40-60% по весу относительно оригинальных JPEG. Это огромно.

JPEG XL — отдельная история. Формат технически превосходит AVIF по скорости декодирования и качеству, но поддержка браузеров пока неполная. Chrome добавил поддержку в версии 110, потом убрал, потом снова добавил. Firefox поддерживает с 113. Safari — с 17. По факту на 2026 год я использую AVIF как основной формат и WebP как фолбэк. JPEG XL пока слежу, но в продакшн не тащу.

Правильная реализация выглядит через тег <picture>:

<picture>
  <source
    srcset="/images/photo.avif"
    type="image/avif"
  >
  <source
    srcset="/images/photo.webp"
    type="image/webp"
  >
  <img
    src="/images/photo.jpg"
    alt="Описание изображения"
    width="800"
    height="600"
    loading="lazy"
    decoding="async"
  >
</picture>

Браузер сам выберет первый поддерживаемый формат. Старые браузеры получат JPEG. Современные — AVIF. Атрибуты width и height обязательны — они предотвращают CLS (Cumulative Layout Shift), что напрямую влияет на Core Web Vitals. Подробнее про это я писал в статье Core Web Vitals: как улучшить показатели.

💡
Автоматическая конвертация в Nginx: Можно настроить Nginx так, чтобы он автоматически отдавал WebP или AVIF, если браузер их поддерживает — без изменений в HTML-коде. Это удобно для legacy-проектов, где менять шаблоны дорого.

Настройка Nginx для оптимальной доставки изображений

Nginx — это первое место, где можно сильно улучшить доставку медиафайлов без каких-либо изменений в самом сайте. Правильные заголовки кеширования, автоматическая отдача WebP, сжатие — всё это настраивается на уровне конфигурации сервера.

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

# Кеширование статических файлов
location ~* \.(jpg|jpeg|png|gif|ico|svg|webp|avif)$ {
    expires 1y;
    add_header Cache-Control "public, immutable, max-age=31536000";
    add_header Vary "Accept-Encoding";
    access_log off;
    
    # Автоматическая отдача WebP если поддерживается
    set $webp_suffix "";
    if ($http_accept ~* "webp") {
        set $webp_suffix ".webp";
    }
    
    # Пробуем отдать WebP-версию, иначе оригинал
    try_files $uri$webp_suffix $uri =404;
}

# Отдельные настройки для видео
location ~* \.(mp4|webm|ogg|mov)$ {
    expires 30d;
    add_header Cache-Control "public, max-age=2592000";
    add_header Accept-Ranges bytes;
    
    # Поддержка range requests для видеоплееров
    proxy_force_ranges on;
    access_log off;
}

# Сжатие для SVG и других текстовых медиаформатов
location ~* \.(svg|svgz)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    gzip_static on;
}

Директива immutable в Cache-Control — это важная деталь, которую многие пропускают. Она говорит браузеру: "этот файл никогда не изменится, не трать время на revalidation даже при обновлении страницы". Но использовать её нужно только вместе с версионированием файлов — иначе пользователи будут видеть старые изображения до истечения срока кеша.

Директива Accept-Ranges bytes для видео критически важна. Без неё видеоплеер не сможет перематывать видео — он будет вынужден скачивать файл с начала. Это особенно заметно на больших файлах.

Оптимизация видео: самая недооценённая область

С видео на сайтах ситуация ещё хуже, чем с картинками. Я регулярно вижу такое: клиент снял видео для главной страницы, видеограф отдал файл в ProRes или H.264 на 60 fps, 4K, 200 МБ. Этот файл загружают прямо на сервер и вставляют через тег <video>. Пользователь с мобильным интернетом открывает сайт и ждёт... ждёт... уходит.

Первое правило: никогда не храни видео на своём сервере, если оно предназначено для просмотра пользователями. YouTube, Vimeo, Cloudflare Stream — это специализированные платформы с CDN, адаптивным битрейтом (HLS/DASH), автоматической транскодировкой. Они делают эту работу в тысячу раз лучше, чем обычный VPS.

Но иногда встроенное видео — это фоновый ролик на главной или небольшой explainer-ролик, и внешние платформы не подходят из-за ограничений (реклама, privacy, брендинг). В таком случае оптимизируй сам. Для этого я использую FFmpeg:

# Конвертация в H.264 для максимальной совместимости
ffmpeg -i input.mov \
  -c:v libx264 \
  -crf 23 \
  -preset slow \
  -movflags +faststart \
  -vf "scale=1920:-2" \
  -c:a aac -b:a 128k \
  output_h264.mp4

# Конвертация в WebM/VP9 (лучшее сжатие, ~30% меньше)
ffmpeg -i input.mov \
  -c:v libvpx-vp9 \
  -crf 33 \
  -b:v 0 \
  -deadline good \
  -cpu-used 2 \
  -vf "scale=1920:-2" \
  -c:a libopus -b:a 96k \
  output_vp9.webm

# Для фоновых видео без звука (ещё меньше размер)
ffmpeg -i input.mov \
  -c:v libx264 \
  -crf 28 \
  -preset slow \
  -movflags +faststart \
  -an \
  -vf "scale=1280:-2" \
  background.mp4

Параметр -movflags +faststart — это обязательно для MP4. Он перемещает метаданные в начало файла, и браузер может начать воспроизведение ещё во время загрузки. Без этого флага видео начнёт играть только после полной загрузки файла.

CRF 23 для H.264 — это хороший баланс качества и размера для большинства случаев. Для фоновых видео можно поднять до 28-30. Для видео с текстом или мелкими деталями — опустить до 18-20.

⚠️
Не используй автовоспроизведение со звуком: Браузеры блокируют автовоспроизведение видео со звуком без взаимодействия пользователя. Фоновые видео всегда должны быть с атрибутами autoplay muted loop playsinline. Иначе видео просто не запустится.

CDN для медиафайлов: это не опция, это необходимость

Честно говоря, я долго скептически относился к CDN для небольших проектов. Казалось, что это "для больших ребят". Потом я подключил Cloudflare к среднему корпоративному сайту с аудиторией по всей России — и TTFB для пользователей из Владивостока упал с 2.3 секунды до 180 миллисекунд. Только за счёт CDN, без изменений на сервере.

Для медиафайлов CDN особенно важен по нескольким причинам. Во-первых, географическая близость: файл отдаётся с ближайшей точки присутствия, а не с сервера в Москве. Во-вторых, CDN умеет правильно кешировать и отдавать файлы с оптимальными заголовками. В-третьих, снимает нагрузку с основного сервера.

Cloudflare — это первый выбор для большинства проектов, потому что бесплатный тариф покрывает базовые нужды. Cloudflare Images (платный) умеет автоматически конвертировать в WebP/AVIF и ресайзить изображения на лету через URL-параметры. Это очень удобно для проектов, где много динамически генерируемых превью.

Подробно о настройке CDN я писал в пошаговом руководстве по настройке CDN — там есть конкретные шаги для Cloudflare, KeyCDN и BunnyCDN.

Для проектов на Битрикс есть нюанс: стандартный модуль CDN в Битриксе работает с несколькими провайдерами, но настройка через nginx и внешний CDN часто эффективнее. Если нужна помощь с этим — занимаюсь поддержкой Битрикс и настройкой инфраструктуры.

Lazy Loading и Responsive Images: детали, которые важны

Lazy loading — это атрибут loading="lazy" на теге <img>. Браузер не загружает изображение, пока оно не попадает в зону видимости. Звучит просто, но есть важные тонкости.

Первое: никогда не ставь loading="lazy" на изображения в первом экране (above the fold). Это замедлит LCP (Largest Contentful Paint) — главный показатель Core Web Vitals. Для первого экрана нужно наоборот — loading="eager" и fetchpriority="high". Я видел сайты, где кто-то лихо поставил lazy loading на все изображения подряд, и LCP вырос с 2.1 секунды до 5.8.

Второе: атрибут srcset для responsive images. Браузер сам выберет нужный размер в зависимости от экрана устройства и плотности пикселей:

<picture>
  <source
    type="image/avif"
    srcset="
      /images/product-400.avif 400w,
      /images/product-800.avif 800w,
      /images/product-1200.avif 1200w
    "
    sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 800px"
  >
  <source
    type="image/webp"
    srcset="
      /images/product-400.webp 400w,
      /images/product-800.webp 800w,
      /images/product-1200.webp 1200w
    "
    sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 800px"
  >
  <img
    src="/images/product-800.jpg"
    alt="Название продукта"
    width="800"
    height="600"
    loading="lazy"
    decoding="async"
  >
</picture>

Атрибут sizes говорит браузеру, какой размер займёт изображение на разных экранах. Это позволяет браузеру правильно выбрать версию из srcset ещё до скачивания файла. Без sizes браузер часто скачивает изображение большего размера, чем нужно.

Подробно про lazy loading и его правильную настройку — в статье Lazy Loading изображений: настройка и ускорение сайта 2026.

ℹ️
decoding="async": Этот атрибут говорит браузеру декодировать изображение асинхронно, не блокируя главный поток. Особенно полезен для больших изображений. Вместе с loading="lazy" даёт заметный прирост к отзывчивости страницы.

Практическая оптимизация в WordPress и Битрикс

На WordPress я обычно использую комбинацию из нескольких инструментов. Для конвертации и оптимизации изображений — Imagify или ShortPixel. Imagify умеет конвертировать в WebP и AVIF прямо при загрузке, генерировать все необходимые размеры и подставлять правильные теги <picture>. ShortPixel делает примерно то же самое, но с немного другим алгоритмом сжатия — по моим тестам на одном проекте разница в качестве минимальна, но ShortPixel чуть агрессивнее сжимает.

Важный момент для WordPress: стандартная функция wp_get_attachment_image() с WordPress 5.5 автоматически добавляет loading="lazy" ко всем изображениям кроме первого. Но fetchpriority="high" нужно добавлять вручную для hero-изображений. Я делаю это через фильтр:

<?php
// Добавляем fetchpriority="high" для первого изображения в контенте
add_filter('wp_get_attachment_image_attributes', function($attrs, $attachment, $size) {
    // Применяем только для hero-изображений (используем data-атрибут как маркер)
    if (isset($attrs['class']) && strpos($attrs['class'], 'hero-image') !== false) {
        $attrs['fetchpriority'] = 'high';
        $attrs['loading'] = 'eager';
        unset($attrs['loading']); // убираем lazy
        $attrs['loading'] = 'eager';
    }
    return $attrs;
}, 10, 3);

// Автоматическая конвертация в WebP при загрузке (если Imagick доступен)
add_filter('wp_handle_upload', function($upload) {
    if (!extension_loaded('imagick')) {
        return $upload;
    }
    
    $mime = $upload['type'];
    $allowed = ['image/jpeg', 'image/png'];
    
    if (!in_array($mime, $allowed)) {
        return $upload;
    }
    
    $file_path = $upload['file'];
    $webp_path = preg_replace('/\.(jpg|jpeg|png)$/i', '.webp', $file_path);
    
    try {
        $imagick = new Imagick($file_path);
        $imagick->setImageFormat('webp');
        $imagick->setImageCompressionQuality(82);
        $imagick->writeImage($webp_path);
        $imagick->destroy();
    } catch (Exception $e) {
        // Логируем ошибку, но не прерываем загрузку
        error_log('WebP conversion failed: ' . $e->getMessage());
    }
    
    return $upload;
});

В Битриксе ситуация немного другая. Встроенная обработка изображений через компонент resize_image умеет делать WebP с версии 22.x. Но AVIF пока не поддерживается из коробки — нужно кастомное решение или обработка на уровне Nginx. Я обычно настраиваю Nginx-конфиг для автоматической отдачи WebP-версий (которые генерирует Битрикс) и дополнительно настраиваю агрессивное кеширование статики через Cache-Control: immutable. Детали по кешированию в Битрикс — в статье настройка кеширования в Битрикс: полное руководство.

Инструменты для анализа и мониторинга медиафайлов

Прежде чем оптимизировать, нужно понять, что именно тормозит. Я использую несколько инструментов в связке.

Google PageSpeed Insights — отправная точка. Он сразу показывает: "Используйте изображения следующего поколения", "Правильно выбирайте размеры изображений", "Отложите загрузку изображений, не отображаемых на экране". По каждому пункту есть конкретные файлы с потенциальной экономией в КБ. Это даёт приоритеты.

WebPageTest (webpagetest.org) — более детальный анализ. Показывает waterfall загрузки, где видно, какие медиафайлы блокируют рендеринг, какой TTFB у каждого ресурса, правильно ли настроено кеширование. Можно тестировать с разных локаций и на разных типах подключения.

Squoosh (squoosh.app) — браузерный инструмент от Google для ручной оптимизации и сравнения форматов. Я использую его когда нужно понять оптимальные настройки качества для конкретного типа изображений проекта. Можно сравнить AVIF vs WebP vs JPEG при одинаковом визуальном качестве и увидеть разницу в размере файла.

Cloudflare Analytics (если используете Cloudflare) — показывает реальную статистику кеш-хитов, сэкономленный трафик, географию запросов. По опыту, правильно настроенный Cloudflare для медиафайлов даёт cache hit rate 85-95%, то есть только 5-15% запросов доходит до вашего сервера.

Для регулярного мониторинга я настраиваю автоматические проверки через Lighthouse CI в CI/CD пайплайне. Это позволяет поймать деградацию производительности до того, как её заметят пользователи или Google. Подробнее про Lighthouse аудит — в статье Lighthouse 2026: аудит и улучшение скорости сайта.

Чек-лист оптимизации медиафайлов

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

Форматы и сжатие:

HTML и атрибуты:

Сервер и CDN:

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

Реальный результат: цифры из практики

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

Интернет-магазин одежды на WordPress (PHP 8.2, MySQL 8.0, ~2000 товаров). До оптимизации: PageSpeed Mobile — 31, Desktop — 58. Суммарный вес страницы категории — 18 МБ, 89% — изображения. После: конвертировали все изображения в AVIF через ShortPixel, настроили Cloudflare с агрессивным кешированием, добавили правильные srcset и lazy loading. Результат: PageSpeed Mobile — 79, Desktop — 94. Вес страницы — 3.2 МБ. LCP с 8.4 секунды до 1.9.

Корпоративный сайт на Битрикс с видео на главной. Видео весило 180 МБ, лежало прямо на сервере. Переконвертировали через FFmpeg: H.264 + WebM, убрали звук (фоновое видео), понизили разрешение с 4K до 1080p. Вес: 180 МБ → 8.4 МБ (H.264) + 6.1 МБ (WebM). Дополнительно настроили preload="none" и загрузку видео только после взаимодействия пользователя на мобильных. PageSpeed Mobile вырос с 29 до 71.

Новостной портал на Laravel (PHP 8.3). Тут была специфическая проблема: тысячи статей со старыми изображениями в PNG и JPEG без lazy loading. Написали консольную команду для пакетной конвертации в WebP через Intervention Image, настроили Nginx для автоматической отдачи WebP-версий. Одновременно добавили loading="lazy" через middleware, который модифицирует HTML-ответ. Экономия трафика — 2.8 ТБ в месяц, PageSpeed вырос в среднем на 22 пункта по всем страницам.

Цифры разные, потому что стартовое состояние у всех разное. Но в среднем грамотная оптимизация медиафайлов даёт +20-40 пунктов PageSpeed и снижение веса страницы в 3-6 раз. Это реально ощутимо и для пользователей, и для SEO — Google прямо учитывает Core Web Vitals в ранжировании.

Хотите ускорить загрузку медиафайлов на вашем сайте?

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

П
Павел
Веб-разработчик · 10+ лет опыта · Bitrix, WordPress, Laravel

Читайте также

Настройка CORS-заголовков на сайте: полное руководство 2026 Сайт не работает — что делать? Laravel для бизнес-проекта: когда и зачем