На этой неделе я столкнулся с интересным классом задач, для решения которых, как я теперь понимаю, можно было использовать гораздо более удачный подход и раньше. Но существует ли такой подход?

Изображение для верхней части сайта
Речь идёт о подготовке изображения, рассчитанного на использовании в верхней правой части сайта jamstackconf.com. Мы, в маркетинговой команде Netlify, используем Figma. Первая моя попытка экспорта этого изображения для использования его на сайте оказалась далеко не самой удачной.
Вот на какие примерные размеры изображения я вышел, экспортировав материалы в формате SVG:
Теперь я знаю, что это — размеры несжатых файлов (до применения к ним алгоритмов сжатия GZIP/Brotli). Но я уверен, что никто не станет со мной спорить о том, что изображение размером 9,9 Мб, пусть и оптимизированное, слишком велико даже для самого старательного алгоритма сжатия (Уточнение: после GZIP-сжатия 9,9 Мб превратились в 7,36 Мб). Учитывая то, что в этом SVG-файле имеется очень много встроенных растровых изображений, с помощью одного лишь SVGOMG как следует этот файл не сжать. Попробуем перейти к растровому изображению и узнать о том, насколько далеко в деле оптимизации изображений нас это может завести.
Вы все знаете меня достаточно хорошо для того чтобы понять, что я не размещу картинку размером 1,2 Мб в очень важном месте страницы. Поэтому я решил заняться оптимизацией. Тут важно учитывать то, что мне надо было сохранить канал прозрачности. В результате, если изменится фоновый цвет страницы, не придётся снова оптимизировать изображение. Этот факт означает, что мы сразу же отказываемся от формата JPEG.
Меня впечатлило то, что, после буквально одного движения мыши, ImageOptim убрал примерно 400 Кб данных из моего изображения. Но итоговые 831 Кб — это всё ещё слишком много.
Вот это уже похоже на что-то приличное. Опция уменьшения цветовой палитры Squoosh (Reduce palette) даёт огромный выигрыш в размерах готового изображения. Ещё я немного поэкспериментировал с параметрами формата AVIF в Squoosh, но формат PNG, всё равно, оказался лучше (Уточнение от 27 августа: обратите внимание на новый раздел с заголовком «Попытка №4: AVIF»).
Поразительная экономия! И этот вариант предусматривает использование тега
Уточнение от 27 августа: Джейк Арчибальд дал мне хороший совет, который заключался в том, чтобы снова попробовать формат AVIF (но в режиме сжатия с потерями), не уменьшая цветовую палитру. Полагаю, что это — очень хорошая идея! Уменьшение цветовой палитры (хотя и даёт значительную экономию размера файла) определённым образом сказывается на готовом изображении. Моей неофициальной целью было получение AVIF-изображения как можно более высокого качества и сохранение при этом размеров файла на уровне WebP-версии с уменьшенной цветовой палитрой.
Вот — отличный материал Джейка про AVIF.
Этот вариант изображения получен при использовании следующих настроек Squoosh:
Если выделить те части изображения, которые хорошо описываются векторными инструментами (градиенты, линии и прочее подобное), и поместить их в SVG-изображение, а всё остальное сохранить в растровом формате, мы можем добиться даже лучших результатов. Пользуясь этим подходом, я, правда, сделал не всё, что было возможно. А именно, перенёс на векторный слой не всё, что можно было туда перенести. Возможно, кто-то решит, пользуясь таким подходом, оставить больше фрагментов изображения на переднем плане, например, на тот случай, если кто-нибудь захочет распечатать страницу (ну — это если кто-то до сих пор выводит веб-страницы на принтерах).

Два слоя изображения
Используя растровый слой как изображение переднего плана, а вспомогательное векторное изображение — в виде того, что задаётся в CSS-свойстве
Тут показаны результаты вышеописанных экспериментов. Полагаю, то, что удалось прийти от исходного изображения размером более 10 Мб к изображению размером в 78 Кб, это — не так уж и плохо. Экономия рассчитана в сравнении с предыдущей попыткой.
Как вы оптимизируете изображения для своих веб-проектов?


Изображение для верхней части сайта
Речь идёт о подготовке изображения, рассчитанного на использовании в верхней правой части сайта jamstackconf.com. Мы, в маркетинговой команде Netlify, используем Figma. Первая моя попытка экспорта этого изображения для использования его на сайте оказалась далеко не самой удачной.
Попытка №1: SVG
Вот на какие примерные размеры изображения я вышел, экспортировав материалы в формате SVG:
- 10,1 Мб — исходный SVG-файл, экспортированный из Figma.
- 9,9 Мб — SVG-файл, оптимизированный с помощью инструмента SVGOMG.
Теперь я знаю, что это — размеры несжатых файлов (до применения к ним алгоритмов сжатия GZIP/Brotli). Но я уверен, что никто не станет со мной спорить о том, что изображение размером 9,9 Мб, пусть и оптимизированное, слишком велико даже для самого старательного алгоритма сжатия (Уточнение: после GZIP-сжатия 9,9 Мб превратились в 7,36 Мб). Учитывая то, что в этом SVG-файле имеется очень много встроенных растровых изображений, с помощью одного лишь SVGOMG как следует этот файл не сжать. Попробуем перейти к растровому изображению и узнать о том, насколько далеко в деле оптимизации изображений нас это может завести.
Попытка №2: PNG
- 1,2 Мб — исходный PNG-файл, экспортированный из Figma.
Вы все знаете меня достаточно хорошо для того чтобы понять, что я не размещу картинку размером 1,2 Мб в очень важном месте страницы. Поэтому я решил заняться оптимизацией. Тут важно учитывать то, что мне надо было сохранить канал прозрачности. В результате, если изменится фоновый цвет страницы, не придётся снова оптимизировать изображение. Этот факт означает, что мы сразу же отказываемся от формата JPEG.
▍ImageOptim
- 831 Кб — PNG-файл, оптимизированный с помощью ImageOptim.
Меня впечатлило то, что, после буквально одного движения мыши, ImageOptim убрал примерно 400 Кб данных из моего изображения. Но итоговые 831 Кб — это всё ещё слишком много.
▍Squoosh
- 376 Кб — PNG-файл, оптимизированный с помощью Squoosh (с применением уменьшенной цветовой палитры, состоящей из 256 цветов).
Вот это уже похоже на что-то приличное. Опция уменьшения цветовой палитры Squoosh (Reduce palette) даёт огромный выигрыш в размерах готового изображения. Ещё я немного поэкспериментировал с параметрами формата AVIF в Squoosh, но формат PNG, всё равно, оказался лучше (Уточнение от 27 августа: обратите внимание на новый раздел с заголовком «Попытка №4: AVIF»).
Попытка №3: WebP
- 152 Кб — WebP-файл, оптимизированный в Squoosh (сжатие без потерь, цветовая палитра уменьшена до 256 цветов).
Поразительная экономия! И этот вариант предусматривает использование тега
<picture>
для прогрессивного перехода с PNG на WebP. Многие могут решить, что этот результат уже «достаточно хорош», но всё то, ради чего я писал этот материал, ещё впереди (и то, что получилось, получилось, и правда, очень хорошо).Попытка №4: AVIF
- 168 Кб — AVIF-файл, оптимизированный в Squoosh (полная цветовая палитра).
Уточнение от 27 августа: Джейк Арчибальд дал мне хороший совет, который заключался в том, чтобы снова попробовать формат AVIF (но в режиме сжатия с потерями), не уменьшая цветовую палитру. Полагаю, что это — очень хорошая идея! Уменьшение цветовой палитры (хотя и даёт значительную экономию размера файла) определённым образом сказывается на готовом изображении. Моей неофициальной целью было получение AVIF-изображения как можно более высокого качества и сохранение при этом размеров файла на уровне WebP-версии с уменьшенной цветовой палитрой.
Вот — отличный материал Джейка про AVIF.
Этот вариант изображения получен при использовании следующих настроек Squoosh:
- Lossless: выключено.
- Quality: 45.
- Subsample Chroma: выключено.
- Effort: 6.
Победитель: два отдельных слоя: SVG + AVIF/WebP/PNG
- 74 Кб + 4,2 Кб — оптимизированные SVG-файл и AVIF/WebP/PNG-файл
Если выделить те части изображения, которые хорошо описываются векторными инструментами (градиенты, линии и прочее подобное), и поместить их в SVG-изображение, а всё остальное сохранить в растровом формате, мы можем добиться даже лучших результатов. Пользуясь этим подходом, я, правда, сделал не всё, что было возможно. А именно, перенёс на векторный слой не всё, что можно было туда перенести. Возможно, кто-то решит, пользуясь таким подходом, оставить больше фрагментов изображения на переднем плане, например, на тот случай, если кто-нибудь захочет распечатать страницу (ну — это если кто-то до сих пор выводит веб-страницы на принтерах).

Два слоя изображения
Используя растровый слой как изображение переднего плана, а вспомогательное векторное изображение — в виде того, что задаётся в CSS-свойстве
background-image
, мы можем скомбинировать эти изображения. Можно даже вернуть оптимизированное растровое изображение обратно в формат SVG, в виде Data URI, внедрённого в <image>
, но я так делать не стал.Итоговые результаты
Тут показаны результаты вышеописанных экспериментов. Полагаю, то, что удалось прийти от исходного изображения размером более 10 Мб к изображению размером в 78 Кб, это — не так уж и плохо. Экономия рассчитана в сравнении с предыдущей попыткой.
Метод | Размер | Экономия |
Исходный SVG | 10,06 Мб | |
SVG, оптимизированный с помощью SVGOMG | 9,92 Мб | -0,14 Мб |
PNG | 1,16 Мб | -8,76 Мб |
PNG, оптимизированный с помощью ImageOptim | 831 Кб | -329 Кб |
PNG, оптимизированный с помощью Squoosh (уменьшенная палитра) | 376 Кб | -455 Кб |
WebP, оптимизированный с помощью Squoosh (уменьшенная палитра) | 152 Кб | -224 Кб |
AVIF, оптимизированный с помощью Squoosh (полная палитра) | 168 Кб | +16 Кб |
Два слоя: SVG (SVGOMG) и AVIF/WebP/PNG (Squoosh) | 78 Кб | -90 Кб |
Как вы оптимизируете изображения для своих веб-проектов?
