Картинки съедают основную часть трафика типичной страницы, и именно на них экономия байтов видна быстрее всего. Между тем на многих сайтах по-прежнему лежит единственный JPEG для всего: для фотографий, скриншотов интерфейса и половины иконок заодно. Форматов давно три, и у каждого свой характер сжатия, своя цена кодирования и своя карта поддержки в браузерах. Разберёмся, чем они отличаются на практике, чем их кодировать и как подключать без риска для старых браузеров.

Три формата с разными характерами сжатия и поддержки

Короткая справка. JPEG царит с 1992 года: потери хорошо сжимают фотографии, но мелкий текст и резкие границы покрываются артефактами, а глубина цвета ограничена восемью битами на канал. WebP вышел в 2010 году на базе кодека VP8: фотографии получаются заметно компактнее, добавились прозрачность, режим без потерь и анимация. AVIF построен на кодеке AV1 и добрался до браузеров позже: Chrome получил поддержку в версии 85 осенью 2020 года, Firefox в версии 93 примерно через год, Safari в версии 16 в 2022-м. Каждый из новых форматов бьёт JPEG по размеру при сопоставимом качестве, а между собой различаются деталями.

Причина выигрыша в устройстве кодеков. JPEG работает с фиксированными блоками восемь на восемь точек, и на границах резких объектов это заметно глазу. AV1 и VP8 предсказывают содержимое соседних областей с переменным размером блока, поэтому ровные участки почти не тратят байты, а сложные получают их с избытком. Отсюда и типичная картина: на фотографиях новые форматы выигрывают ощутимо, на графике с плоскими заливками разница меньше, зато AVIF добавляет глубину цвета до двенадцати бит, что важно для широких градиентов и цветных материалов повышенного диапазона.

| Формат | Прозрачность | Анимация | Глубина цвета | Прогрессивный показ | Скорость кодирования |
|---|---|---|---|---|---|
| JPEG | нет | нет | 8 бит | да | высокая |
| WebP | да | да | 8 бит | нет | средняя |
| AVIF | да | да | до 12 бит | нет | низкая |

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

О порядке величин стоит сказать аккуратно. По опубликованным замерам разработчиков WebP экономия против JPEG при том же видимом качестве доходит до четверти, а то и трети размера файла. AVIF на фотографиях сжимает обычно ещё заметнее, особенно на крупных изображениях с плавными областями. Точные проценты зависят от конкретной картинки, поэтому честная оценка делается на своих материалах: одна и та же фотография в разных кодировщиках при одинаковой визуальной оценке даёт разные соотношения. Зато направление выигрыша стабильно на всех коллекциях, которые встречаются на практике.

Подбор формата под тип изображения вместо моды

Фотографии и обложки с плавными переходами лучше всего отдаются AVIF и WebP: оба любят мягкие градиенты. Скриншоты интерфейсов и графика с текстом выигрывают от режима без потерь WebP либо остаются в PNG, потому что артефакты сжатия с потерями на мелком шрифте заметнее всего. Иконки и схемы это территория SVG, векторного формата, который масштабируется без потерь и весит копейки. JPEG остаётся запасным вариантом и территорией старых устройств. Правило простое: сначала вопрос о том, что это за картинка, и только потом вопрос о том, в какой формат её завернуть.

Пара нюансов усиливает эффект. Экраны с повышенной плотностью точек прощают более низкое качество исходника, поэтому кодировщик настраивают под целевое отображение, а не под пиксельную точность. Прозрачность раньше означала PNG и его солидный вес, теперь она встроена и в WebP, и в AVIF, и на логотипах с плавающими фонами разница достигает раз. Анимированные баннеры тоже переезжают с GIF без потерь в кадрах.

Формат лишь половина работы, вторая половина это размер. Картинка на 4000 точек шириной, ужатая в браузере до 700, переплачивает за пиксели, которые никто не увидит. Поэтому каскад размеров не менее важен, чем каскад форматов: два-три варианта ширины под мобильный экран, планшет и десктоп закрывают почти все случаи. Сочетание двух форматов и трёх ширин даёт шесть файлов на картинку, и это не расточительство, а ровно тот набор, который браузер выбирает сам по разметке ниже.

Разметка picture с каскадом источников и запасным JPEG

Браузер выбирает формат сам, если ему предложить каскад источников в правильном порядке:

<picture>
  <source srcset="/hero-1280.avif 1280w, /hero-1920.avif 1920w" type="image/avif">
  <source srcset="/hero-1280.webp 1280w, /hero-1920.webp 1920w" type="image/webp">
  <img src="/hero-1280.jpg" srcset="/hero-1280.jpg 1280w, /hero-1920.jpg 1920w"
       sizes="(max-width: 700px) 100vw, 700px"
       width="1280" height="720"
       loading="lazy" decoding="async"
       alt="Панорама горного перевала на рассвете">
</picture>

Обход идёт сверху вниз, и браузер берёт первый понятный тип. Атрибуты width и height сообщают пропорции до загрузки и убирают прыжки макета, атрибут sizes подсказывает реальную ширину картинки на экране, а loading со значением lazy отодвигает загрузку невидимых кадров. Запасной JPEG в img обязателен: поддержка AVIF дошла до всех современных браузеров, но доля старых версий Safari у конкретной аудитории проверяется статистикой, а не верой.

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

Для главной картинки первого экрана добавляется ещё один инструмент: предварительная загрузка. Ссылка с атрибутами imagesrcset и imagesizes в разметке документа заставляет браузер начать скачивание hero-изображения до того, как он построит макет и доберётся до тега img. На медленных каналах это срезает заметную долю времени до показа главного кадра, и настройка занимает одну строку разметки.

Конвейер кодирования на сборке с рабочими настройками

Для ручных проб хватает консольных кодировщиков:

cwebp -q 80 photo.jpg -o photo.webp
avifenc -q 45 -s 6 photo.jpg photo.avif

Шкалы качества у кодировщиков разные, и переносить цифру из одного в другой наивно. У cwebp качество лежит в диапазоне от 0 до 100, привычный рабочим режим для фотографий находится около восьмидесяти. У avifenc та же ручка выражается величиной квантизатора от 0 до 63, где меньше означает лучше, и фотографическое качество обычно достигается в середине шкалы. Подбирают всегда по глазам на своих картинках, а не по рецепту из чужой статьи.

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

const sharp = require('sharp');

await sharp('photo.jpg')
  .resize(1280, null, { withoutEnlargement: true })
  .avif({ quality: 45, effort: 4 })
  .toFile('photo-1280.avif');

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

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

Ошибки перехода, которые съедают всю выгоду

Первая и самая частая ошибка это кодирование из уже сжатого JPEG. Каждый проход с потерями накапливает артефакты, поэтому исходником служит мастер без потерь, а не очередной JPEG с чужого сайта. Вторая ошибка это единая цифра качества для всех форматов: шкалы несравнимы, и где-то картинка окажется мыльной, а где-то излишне тяжёлой. Третья это запасной формат, о котором забыли: без него старые браузеры показывают пустые рамки, и выигрыш в байтах оплачивается жалобами.

Четвёртая ошибка касается кэша и уже описанного заголовка Vary: раздача без него подменяет версии между пользователями. Пятая это перекос в мелочи: кодировать иконку размером три килобайта в AVIF занятие пустое, когда рядом с ней лежит фотография на четыреста килобайтов. Шестая это тяжёлая сборка: кодирование всего архива в AVIF на каждый деплой растягивает релизы, поэтому кэширование результатов конвейера не пожелание, а требование. Каждая из ошибок стоит копейки на этапе настройки и дорого в эксплуатации, поэтому чек-лист перехода разумно прогонять целиком, а не по памяти. Финальная проверка делается не по уверенности в разметке, а по факту: панель сети в инструментах разработчика показывает тип содержимого каждой отдачи, и именно он, а не расширение файла, говорит, какой формат реально получил браузер. Пять минут такой сверки после выката экономят неделю расспросов о том, почему трафик не уменьшился.

Старый JPEG, который ещё рано списывать со счетов

JPEG проигрывает в размерах, но держит позиции, которые новым форматам не отнять. Прогрессивное кодирование даёт быстрое грубое изображение ещё до полной загрузки, что приятно ощущается на медленных каналах. Поддержка охватывает вообще всё, что умеет показывать картинки, включая почтовые клиенты и встроенные просмотрщики. Кодировщики вроде mozjpeg выжимают из старого формата дополнительный процент, и для запасного варианта это бесплатная экономия.

Даже артефакты JPEG здесь превращаются в плюс: на фотографии они привычны глазу и редко заметнее, чем выигрыш в байтах, а на тексте и графиках место JPEG давно заняли другие форматы. Скромный ветеран не победитель, а общий знаменатель, и именно эту роль он выполняет в каскаде picture. Экспериментальные наследники вроде JPEG XL пока не добрались до повсеместной поддержки в браузерах, поэтому разговор о них остаётся академическим.

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

Порядок внедрения для существующего сайта

Внедрение на живом сайте разумно разложить на шаги:

  1. Снять инвентаризацию: какие форматы и размеры раздаются сейчас и какая доля трафика приходится на изображения;
  2. Выбрать первую партию из самых тяжёлых фотографий и прогнать её через новые кодировщики, сравнив размер и видимое качество;
  3. Собрать каскад picture с запасным JPEG и проверить разметку на старых браузерах;
  4. Встроить кодирование в конвейер сборки с кэшированием результатов;
  5. Настроить заголовки кэша с учётом Vary и следить за метриками скорости страниц после выката.

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

Итоговый расклад выглядит трезво. AVIF берут там, где каждый килобайт на счету: витрины, галереи, крупные обложки. WebP покрывает остальное универсально и быстро кодируется в конвейере. JPEG остаётся страховочным тросом и единственным выбором там, где нельзя рисковать совместимостью. Попытка обойтись одним форматом на весь сайт не отменяет этих ролей, а лишь переносит расходы: переплата трафиком, риск совместимости или вечная сборка. Форматы не спорят между собой, они делят работу, и хорошо настроенный каскад незаметен пользователю ровно потому, что работает.