Мы перевели 226 картинок сайта из PNG в WebP и получили экономию около 96%: 188 мегабайт превратились в 7,2. Заодно наткнулись на граблю, из-за которой картинка на странице может пропасть совсем - расскажем, как её обойти.
Вопрос формата картинок всплывает на любом сайте, который живёт больше года: иллюстрации, скриншоты и фотографии кейсов копятся в папке, и вес страницы растёт быстрее текста на ней. Вес напрямую влияет на Core Web Vitals, в частности на LCP - об этом пишет и документация Google для разработчиков. Из чего вообще складывается время загрузки, мы разбирали в статье про ускорение сайта. Перевод в WebP - одна из немногих техник, которая даёт ощутимый результат без переписывания вёрстки.
Чем WebP отличается от PNG и JPEG
PNG хранит картинку без потерь и отлично подходит для плоской графики, но вес растёт вместе с количеством деталей и цветов. JPEG сжимает с потерями и хорошо работает на фотографиях, но не поддерживает прозрачность и требует подбирать качество на глаз. WebP - кодек, который умеет сжимать без потерь, как PNG, и с потерями, как JPEG, а ещё поддерживает прозрачный фон. При сопоставимом визуальном качестве файл получается заметно легче любого из старых форматов. Поддержка в браузерах давно повсеместная - отдельно беспокоиться об этом не нужно.
Как мы считали: 226 файлов, 188 МБ стали 7,2 МБ
На своём сайте мы прогнали через конвертацию весь каталог сгенерированных иллюстраций и скриншотов - 226 файлов PNG. Суммарный вес до конвертации был 188 МБ, после - 7,2 МБ, экономия около 96%. Секрет в составе каталога: почти весь объём занимала плоская векторная графика с двумя-тремя основными цветами, а такую картинку WebP сжимает почти идеально. Несколько фотографий в карточках кейсов дали куда более скромный результат - там счёт шёл на десятки процентов, а не на разы.
Почему на плоской графике выигрыш почти стопроцентный, а на фото скромнее
Разница в том, как устроена картинка внутри. PNG без потерь хранит каждый пиксель, и на однотонных заливках это избыточно: соседние пиксели почти всегда одного цвета, а формат описывает их по отдельности. WebP умеет находить эту повторяемость и сворачивать ровные области в компактную запись, поэтому на иллюстрациях, иконках и скриншотах экономия доходит до 95-98%. У наших иллюстраций из блога, которые мы делаем нейросетью в едином стиле (писали об этом в статье про единый стиль иллюстраций), много плавных заливок и градиентов, и они сжимаются почти без остатка. Фотография устроена иначе: в ней много шума и мелких деталей, которые уже не так избыточны, поэтому выигрыш на снимках держится в пределах 25-40%.
Как переводить массово: качество, пропуск готового, повторная перезапись
Конвертировать сотни файлов вручную бессмысленно - нужен пакетный прогон. На практике удобная связка такая:
- Качество сжатия около 80. Артефакты на глаз не видны даже на плоской графике, а вес уже близок к минимуму. Качество 100 почти не нужно: вес выходит куда больше, а разница на глаз не видна.
- Пропуск уже сконвертированных файлов. Скрипт проверяет, есть ли рядом с PNG одноимённый WebP, и если да - не трогает его. Повторный прогон после добавления десятка новых картинок не тратит время на все двести с лишним старых.
- Режим принудительной перезаписи. Отдельный флаг, который включают осознанно: например, если поменяли качество сжатия или заменили исходную картинку под тем же именем, а старый WebP устарел.
Исходники не удаляем. PNG остаётся на диске как запасной вариант, и весит он на фоне сэкономленных мегабайт совсем немного.
Разметка: два источника и запасной вариант
Наличие WebP-файла само по себе ничего не меняет, пока браузеру не сказали, что он есть. Для этого используется тег picture с несколькими source:
<picture>
<source type="image/webp" srcset="/img/blog/example.webp">
<img src="/img/blog/example.png" alt="Описание картинки" loading="lazy">
</picture>
Браузер читает source по порядку и берёт первый формат, который умеет показывать. Современные браузеры поддерживают WebP; img с PNG внутри picture работает как запасной вариант для старых версий и как единственный источник для скринридеров. С точки зрения разметки картинка ведёт себя как обычная img: тот же alt, то же поведение при обтекании текстом.
Грабля: файла нет на сервере - и картинка просто пропадает
Тут кроется самая неприятная часть истории. Если в разметке стоит source с типом WebP, а самого файла на сервере нет, браузер не откатится на PNG из img ниже: он решит, что формат поддерживает, попробует скачать, получит ошибку и покажет битую картинку - пустой прямоугольник вместо иллюстрации. Резервный img спасает только тогда, когда браузер сам не умеет WebP, а не тогда, когда не хватает конкретного файла.
У нас так и случилось: во время одной из выкладок PNG обновили, а вместе с ним забыли перегенерировать и залить свежий WebP. Страница со старой картинкой продолжала работать, потому что WebP там был, а на странице, добавленной чуть позже, картинка пропала полностью - PNG для неё существовал, а WebP не успели создать. Обнаружили не сразу. Визуально дефект похож на обычную неполадку загрузки, а не на ошибку вёрстки.
Проверить весь каталог на такую нехватку можно одной командой: сравнить список файлов с расширением png и список файлов с расширением webp в одной папке и найти те имена, которым не хватает пары. Это быстрее, чем открывать страницы вручную, и ловит проблему до жалобы от заказчика.

