Оптимизация графики для web

Это перевод статьи Image Optimization автора Estelle Weyl.

Наверное, каждый веб-разработчик знает, что когда речь заходит о производительности и удобстве ипользования (UX) каждое изображение на странице имеет огромное значение: первые плоды в оптимизации web-страниц может принести именно работа с изображениями. Использование методик сжатия изображений без потерь качества позволяет снизить суммарный размер страницы не нанося ущерба пользовательскому опыту (UX) работы с такими страницами, тем самым, улучшая производительность и увеличивая конверсию. Существует много методов для определения того, какие изображения поддерживаются, и вам остается только подготовить “правильные” изображения и отдать их пользователю. Создание оптимальных изображений для всех пользователей на всех типах устройств должно стать целью всех разработчиков (доступность должна стать еще одной целью, но сейчас не об этом).

Как определить какое изображение показать

Существует несколько методик для отображения нужного изображения, например, медиа запросы при использовании фоновых изображений, или использование элементов <picture> и <source> совместно с srcset.
Используя CSS @media queries можно отображать различные фоновые изображения в зависимости от размера окна просмотра или плотности пикселей на устройстве пользователя.

Например, вы можете показать изображение lowres.jpg для старых ноутбуков и hires.jpeg для iPad Pro:

1
2
3
4
5
6
7
8
9
header {
background-image: url(img/hires_header.jpg);
}

@media only screen and (min-device-pixel-ratio: 2) and (min-width: 1024px) {
header {
background-image: url(img/hires_header.jpg);
}
}

А как быть с обычными изображениями переднего плана?

Методика адаптивных изоражений еще с 2013 года была основана на том, что SVG имеет свою свобственную ширину и высоту контейнера, и медиавыражения в них отталкиваются от этих размеров, а не от размеров окна браузера (viewport).
К счастью, текущая поддержка браузерами тега <picture> и srcset позволяют не использовать уже этот хак.

Основоной проблемой в изображениях переднего плана является то, что браузер имеет информацию о размере экрана (viewport) и плотности пикселей на экране, но понятия не имеет о размере загружаемого изображения и того, как оно соотносится с размером экрана. Но, разработчик знает и может указывать их.

Подобно медиазапросам при помощи тегов <picture, <source> и атрибута srcset разработчик может диктовать браузеру какие изображения отображать для того или иного размера экрана или плотности пикселей.

1
2
3
4
5
6
<picture>
<source srcset="small_lowres.jpg, small_highres.jpg 2x" media="(max-width: 768px)">
<source srcset="default.jpg, default_highres.jpg 2x">
<source srcset="large_lowres.jpg, large_highres.jpg 2x" media="(min-width: 1024px)">
<img src="default.jpg" alt="image descriptor">
</picture>

Примечание! Всегда используйте по умолчанию тег <img> внутри каждого <picture>, а также атрибут alt для тега.

Вы можете использовать просто тег <img> без использования <picture> и в теге img указать атрибуты srcset с набором изоражений и sizes для описания области их применения.

1
2
3
4
5
6
7
8
<img src="default.jpg"
srcset="large.jpg 1024w,
medium.jpg 768w,
default.jpg 420w"
sizes="(min-width: 1024px) 1024px,
(min-width: 768px) 90vw,
100vw"
alt="image descriptor" />

Мы также можем отображать различные типы изображений используя атрибут type:

1
2
3
4
5
6
<picture>
<source srcset="photo.jxr" type="image/vnd.ms-photo">
<source srcset="photo.jp2" type="image/jp2">
<source srcset="photo.webp" type="image/webp">
<img srcset="photo.jpg" alt="My beautiful face">
</picture>

Если вас удивляет код выше, JPEG-XR старый MIME image/vnd.ms-photo для Windows Media Photo, проприетарный формат изображений от Microsoft, поддерживаемый IE8 и выше, включая Microsoft Edge. jp2 – это расширение для формата JPEG 2000, который поддерживается браузером Safari. WebP – это формат изоюражений со сжатием без потерь качества и поддерживается на данный момент браузерами Chrome и Opera. А Firefox будет поддерживать форматы графики, как PNG-A, SVG, GIF и JPEG (как в коде выше).

ChromeWebP
IE 9+ / EdgeJPEG-XR
OperaWebP
SafariJPEG-2000

Для Firefox и IE8 нужно предусмотреть запасной вариант в виде изображений JPEG или PNG. И хотя Safari и Firefox экспериментируют с поддержкой WebP изображений, пока нет уверенности в том, что такая поддержка вскоре появится. В любом случае, можно проверить поддержку на сайте Can I Use.

Для более детального изучения возможностей есть хорошие онлайн учебники для медиавыражений, тега <picture> и srcset.

Сложность и количество кода

Основной пролемой в таком решении (смотри код выше), это большое количество кода, который необъодимо написать для того, чтоб покрыть как можно больше вариантов размеров экранов и плотностей пикселей. Расставить контрольные точки для каждого разрешения безусловно можно, но это сложно, и вы врядли хотели бы этим заниматься вручную. К счастью, для написания таких условий можно и нужно автоматизировать.

Оптимальным решением в том случае будет генерация кода на стороне сервера под три из четырех основных критериев, таких как: размер окна (viewport), плотность пикселей, поддержка клиентом формата изображения и отношение размера изображения к размеру экрана. Почему три из четырех? Вы всегда можете использовать все преимущества понимания браузером sourcesets, но вы не используете все комбинации, а лишь некоторые из них.

Если ваш DOM формируется в браузере только на клиентской стороне при помощи JavaScript, например, как у React приложений, имея информацию о клиентском устройстве вы можете запросить правильное изображение, но пользователи будут какое-то время видеть частично загруженный экран (в то время, пока обрабатывается код на клиенте).

Скриншот профайлера Google Chrome

В том случае, когда вы не генерируете весь HTML на стороне клиента, подмена пути к изображению тоже не будет оптимальным решением, так как во время парсинга документа браузер начнет скачивать оригинальное изображение, а затем, когда отработает JavaScript, браузер приступит к скачиванию другого, более оптимального для него, изображения.

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

К сожалению, подсказки, которые отправляются на сервер с информацией о плотности пикселей экрана или поддержкой WebP, в виде заголовков HTTP запросов были реализованы только в Blink (Chrome и Opera). Когда вы имеете информацию о разрешении и размере экрана пользователя вы можете автоматически отдавать правильные изображения используя прогрессивное улучшение на стороне сервера. При помощи таких заголовков мы можем определить поддержку формата изображения WebP (Chrome и Opera поддерживают такие типы заголовков), разрешение и размер окна устройства клиента. В Instart Logic у нас есть скрипт под названием Nanovisor, который повторяет функциональность HTTP заголовков для браузеров, которые не поддерживают эту технологию, что позволяет нам отправлять клиенту оптимизированные изображения.

Вы можете также анализировать строку загловка UserAgent вместе с некоторой дополнительной информацией для того, чтобы определить тип поддерживаемых графических файлов у конкретного пользователя. Узнав это, вы можете подменить расширение файла или можете отдать изображение нужного формата но с “неправильным” расширением. Например, если пользователь запросил файл foo.jpg мы можем отдеть ему нужный тип файла, под все тем же именем foo.jpg. В Instart Logic мы отдаем пользователям WebP для Chrome и Opera, и JPEG-XR для Edge без изменения имени файла, мы просто всегда используем .jpg в конце имени файла. Мы пользуемся тем фактом, что все браузеры корректно отображают изображения руководствуясь MIME не обращая внимания на расширение файлов. Таким образом, мы можете создавать одну и туже разметку html для разных браузеров, а со стороны сервера отдавать кажому браузеру нужное изображение.

Если вы собираетесь генерировать различные форматы изображений на основе поддерки браузером, но с одним расширением файла, вы должны обеспечить сохранение (кеш) изображений на стороне сервера и как-то разделять изображения с одним именем и разным типом содержимого. Либо вам нужно со стороны клиента слать запросы с нужных разширением файла. Если вы знаете лучшее или еще одно решение, дайте мне знать.

Автоматизация процесса

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

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

Процесс оптимизации изображений может занимать много времени, особенно для сайтов с динамическим содержимым, где количество может исчисляться тысячами, сотнями тысяч или даже миллионами изображений с различными размерами и типами. И в этом случае может помочь программное обеспечение, например, ImageMagick. ImageMagick позволяет конвертировать изображения в различные форматы, такие как: PNG, JPEG, JPEG-2000, GIF и даже WebP. Поддеривается еще множество форматов и конвертировать изображения можно используя командную строку:

1
convert myImg.jpg -quality 78 -define webp:lossless=true myImg.webp

Приведенная выше команда сохранит копию изображения myImg.jpg в формате WebP, при этом конвертирование будет осуществлено без видимых потерь до качества 78%.
Так же, при помощи ImageMagic вы можете изменить размер изображения используя флаг -resize

1
convert myImg.jpg -quality 78 -resize 50% myImg.webp

Приведенная выше команда создаст новый файл в формате WebP размером 50% от оригинального изображения (myImg.jpg) и качеством 78%.

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

Задача поиска оптимального качества для каждого изображения будет занимать очень много времени или требовать использования большого количества людей. Потому, большинство инструментов для преобразования изображений уменьшают размер файла за счет ухудшения качества изображения, используя общий коэффициент сжатия. Например, когда я оптимизировал изображения для своего сайта с несколькими картинками, я индивидуально подобрал степерь сжатия для них в пределах от 35% до 88%. Для галерей и других проектов с множествами изображений я использовал Adobe Fireworks для автоматизации процесса конвертации и сохранял все изображения с качеством 78%. Большинство программ для автоматизации оптимизации сохраняют изображения с качеством около 80%. Основываясь на своем опыте я выбираю обычно качество 78%. Тем не менее, нет какого-то магичесого универсального числа для выбора качетсва изображения.

Уровень сжатия сильно зависит от того, что изображено на картинке и, в целом, зависит от уровня детализации. И в зависимости от содержания нужно выставлять степерь сжатия. Чем более детализировано изображение, тем ниже должна быть степерь сжатия (в районе 90%), в то время как изображения с меньшим количеством детализированных участков будут отлично выглядеть даже при качестве ниже 50%.

Не исключается и автоматизированная настройка качества изображения. Так, платформа Instart Logic’s использует компьютерное зрение и машинное обучение для контентно-зависимой оптимизации изображений. Изображения оптимизируются с учетом размеров и возможностей браузера, качества интернет соединения и оптимальных коэффициентов сжатия изображения без видимых потерь качества. Процесс автоматизированной оптимизации качества изображения, то что мы называем “SmartVision”, строится на основе алгоритмического подхода и машинного обучения для получения адаптивных настроек для каждого изображения в отдельности с наилучшими сочетаниями качества изображения и его веса. Усовершенствованные алгоритмы компьютерного зрения позволяют увеличить процент сжатия изображения без видимых потерь качества. Parvez Ahammad в своей статье еще в 2014 году описал эти алгоритмы.

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

От переводчика

В 2015 году я опубликовал статью webp - уже пора?, в которой описал возможности относительно нового на тот момент формата изображения WebP. Спустя более чем полтора года поддержкой формата WebP все еще могут похвастать лишь Chrome и Opera. Но, использование этого формата на нескольких крупных проектах в AlterEGO зарекомендовало себя очень положительно. Мы снизили потребление трафика, загрузку канала и скорость загрузки страниц сайта. При этом, изображения не потеряли в качестве. А это очень важно, например, для интернет магазинов, где от качества изображения напрямую могут зависеть продажи.

Основной проблемой, с которой нам довелось столкнуться при использовании оптимизированных изображений стала проблема производительности. Большой объем графических файлов (фото для товаров) и постоянные обновления фото не позволяли выполнять прегенерацию. Более того, использование оптимального размера изображения (в зависимости от плотности пикселей экрана и размеров viewport) сделало обязательным условие генерации изображения “по запросу”. Т.е. на лету. Предложенное в моей статье решение с использванием php и библиотеки Imagick для изменения размеров и формата изображений оказалось бесполезным. Время генерации изображения было слишком большим и оно еще больше увеличивалось с увеличением количества запросов. Проблему удалось решить при помощи модуля PageSpeed для NGINX и организации кеширования и сохранения сгенерированных изображений на диск. Нам удалось добиться максимального времени генерации изображений в районе 500мс при среднем времени повторной отдачи изображения за 25-30мс. Но, это тема для отдельной статьи.

Proudly powered by Hexo and Theme by Hacker
© 2018 Denis Zavgorodny