От автора: в этом посте я опишу 8 методов оптимизации загрузки изображений, чтобы минимизировать использование для отображения изображений как пропускного канала, так и ЦП. Я представлю их в виде аннотированного примера HTML, чтобы людям было легче воспроизвести результаты.
Некоторые из этих методов более устоявшиеся, другие в некоторой степени новы. В идеале, ваш любимый механизм для публикации веб-документов (например, CMS, генератор статических сайтов или фреймворк) реализует все эти готовые возможности. В конце этого поста я буду обновлять список технологий, обеспечивающих все описанные здесь оптимизации.
Вместе эти методы оптимизируют все элементы Core Web Vitals от Google за счет:
Сведения к минимуму Largest Contentful Paint (LCP) с помощью уменьшения количества байтов, кэширования и отложенной загрузки.
Сохранения кумулятивного сдвига макета (CLS) равным нулю.
Уменьшения задержки первого ввода (FID) за счет уменьшения загрузки ЦП (основного потока).
Методы оптимизации
Адаптивный макет
Это хорошо понятный метод, позволяющий использовать доступное горизонтальное пространство до максимального размера изображения при сохранении соотношения сторон. Новым в 2020 году является то, что веб-браузеры резервируют правильное вертикальное пространство для изображения до его загрузки, если атрибуты width и height правильно заданы для элемента img. Это позволяет избежать кумулятивного сдвига макета (CLS).
1 2 3 4 5 6 7 8 |
<style> img { max-width: 100%; height: auto; } </style> <!-- Providing width and height is more important than ever. --> <img height="853" width="1280" ... /> |
Отложенный рендеринг
Вторая техника более актуальна. Новый атрибут CSS content-visibility: auto указывает браузеру не беспокоиться о макете изображения, пока оно не приблизится к экрану. Это имеет все виды преимуществ, но наиболее важным из них может быть то, что браузер не будет беспокоиться о декодировании нашего размытого изображения-заполнителя или самого изображения, если это не нужно, уменьшая нагрузку на процессор. К сожалению, если мы не предоставим сопутствующее свойство CSS contain-intrinsic-size, это вызовет CLS. И еще, к сожалению, оно не поставляется с выводом соотношения сторон от атрибутов width и height и, следовательно, мы должны обеспечить относительно сложное значение, которое вычисляет пространство для изображения, которое должен резервировать браузер.
Формула в этом случае должна работать, если вы предоставите переменную CSS —main-width, которая описывает ширину основного раздела документа. 1280px это максимальная ширина изображения, 853px максимальная высота и 0.66640625 соотношение сторон.
1 2 3 4 5 6 7 |
<style> /* This probably only makes sense for images within the main scrollable area of your page. */ main img { /* Only render when in viewport */ content-visibility: auto; } </style> |
AVIF
AVIF — это самый последний формат изображений, который получил распространение в веб-браузерах. В настоящее время он поддерживается в браузерах Chromium и доступен с пометкой в Firefox. Поддержка Safari пока недоступна, но, учитывая, что Apple является членом группы, стоящей за форматом, мы можем ожидать поддержки в будущем.
AVIF примечателен тем, что он постоянно превосходит JPEG по очень значительным показателям. Это отличается от WebP, который не всегда создает изображения меньшего размера, чем JPEG, и на самом деле может привести к проблемам из-за отсутствия поддержки прогрессивной загрузки.
Чтобы реализовать прогрессивное улучшение для AVIF, используйте элемент picture. Фактически элемент img вложен в picture. Это может сбивать с толку, потому что img иногда описывается как резервный вариант для браузеров без поддержки изображений, но в основном этот элемент picture помогает только при выборе src, но не имеет самого макета. Отрисовываемый элемент (и стиль, который вы задаете) является элементом img.
До недавнего времени было относительно сложно кодировать изображения AVIF на стороне сервера, но с последней версией библиотек, таких как Sharp, это теперь просто.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<picture> <source sizes="(max-width: 608px) 100vw, 608px" srcset=" /img/Z1s3TKV-1920w.avif 1920w, /img/Z1s3TKV-1280w.avif 1280w, /img/Z1s3TKV-640w.avif 640w, /img/Z1s3TKV-320w.avif 320w " type="image/avif" /> <!-- snip lots of other stuff --> <img /> </picture> |
Загрузка нужного количества пикселей
Вы, возможно, заметили атрибуты srcset и sizes в фрагменте выше. Используя селектор w, он сообщает браузеру, какой URL-адрес использовать на основе физических пикселей, которые будут использоваться, если изображение будет выводиться на устройстве пользователя с учетом ширины, рассчитанной на основе атрибута sizes (который является выражением медиа-запроса).
При этом браузер всегда будет загружать изображение минимального размера, обеспечивающее наилучшее качество изображения для пользователя. Или он может выбрать изображение меньшего размера, если, например, пользователь выбрал какой-либо режим сохранения данных.
Резервные
Предоставьте больше исходных элементов с помощью srcset для браузеров, которые поддерживают только устаревшие форматы изображений.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<source sizes="(max-width: 608px) 100vw, 608px" srcset=" /img/Z1s3TKV-1920w.webp 1920w, /img/Z1s3TKV-1280w.webp 1280w, /img/Z1s3TKV-640w.webp 640w, /img/Z1s3TKV-320w.webp 320w " type="image/webp" /> <source sizes="(max-width: 608px) 100vw, 608px" srcset=" /img/Z1s3TKV-1920w.jpg 1920w, /img/Z1s3TKV-1280w.jpg 1280w, /img/Z1s3TKV-640w.jpg 640w, /img/Z1s3TKV-320w.jpg 320w " type="image/jpeg" /> |
Кеширование / неизменяемые URL-адреса
Указание хэш байтов в изображение в URL-адрес изображения. В приведенных выше примерах я делаю это с URL-адресами Z1s3TKV в изображениях. Таким образом, URL-адрес изменится, если изображение изменится, и, соответственно, вы можете применить бесконечный срок действия кеша для изображений. Вы хотите, чтобы ваши заголовки кеширования выглядели примерно так cache-control: public,max-age=31536000,immutable.
Immutable – семантически правильное значение cache-control, но, к сожалению, оно не поддерживается широко в браузерах (я имею в виду, Chrome). max-age=31536000 – это откат к кешированию на год. public важно, чтобы ваш CDN мог кэшировать изображение и доставлять его. Но используйте это только в том случае, если это целесообразно с точки зрения конфиденциальности.
Отложенная загрузка
Добавление loading=»lazy» к img указывает браузеру начинать выборку изображения только по мере того, как оно приближается к экрану и, вероятно, будет фактически отображаться.
1 |
<img loading="lazy" ... /> |
Асинхронное декодирование
Добавление decoding=»async» к img дает браузеру разрешение на декодирование изображения вне основного потока, избегая воздействия на пользователя процессорного времени, используемого для декодирования изображения. У этого не должно быть заметных недостатков, за исключением того, что это не всегда может быть значением по умолчанию.
1 |
<img decoding="async" ... /> |
Размытый заполнитель
Размытый заполнитель — это встроенное изображение, которое дает пользователю некоторое представление об изображении, которое в конечном итоге загрузится, не требуя выборки байтов из сети.
Некоторые примечания по реализации представлены здесь:
Он вставляет размытый заполнитель как часть изображения background-image. Это позволяет избежать использования второго элемента HTML и, естественно, скрывает заполнитель при загрузке изображения, поэтому для реализации этого не требуется JavaScript.
Он обертывает URI данных фактического изображения в URI данных изображения SVG. Это сделано потому, что размытие изображения выполняется на уровне SVG, а не через фильтр CSS. В результате размытие выполняется только один раз для каждого изображения при растрировании SVG.
1 2 3 4 5 6 7 8 9 10 11 |
<img style=" ... background-size: cover; background-image: url('data:image/svg+xml;charset=utf-8,%3Csvg xmlns=\'http%3A//www.w3.org/2000/svg\' xmlns%3Axlink=\'http%3A//www.w3.org/1999/xlink\' viewBox=\'0 0 1280 853\'%3E%3Cfilter id=\'b\' color-interpolation-filters=\'sRGB\'%3E%3CfeGaussianBlur stdDeviation=\'.5\'%3E%3C/feGaussianBlur%3E%3CfeComponentTransfer%3E%3CfeFuncA type=\'discrete\' tableValues=\'1 1\'%3E%3C/feFuncA%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Cimage filter=\'url(%23b)\' x=\'0\' y=\'0\' height=\'100%25\' width=\'100%25\' xlink%3Ahref=\'data%3Aimage/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAGCAIAAACepSOSAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAs0lEQVQI1wGoAFf/AImSoJSer5yjs52ktp2luJuluKOpuJefsoCNowB+kKaOm66grL+krsCnsMGrt8m1u8mzt8OVoLIAhJqzjZ2tnLLLnLHJp7fNmpyjqbPCqLrRjqO7AIeUn5ultaWtt56msaSnroZyY4mBgLq7wY6TmwCRfk2Pf1uzm2WulV+xmV6rmGyQfFm3nWSBcEIAfm46jX1FkH5Djn5AmodGo49MopBLlIRBfG8yj/dfjF5frTUAAAAASUVORK5CYII=\'%3E%3C/image%3E%3C/svg%3E'); " ... /> |
Оптимизация JavaScript (необязательно)
Браузеры могут чувствовать себя обязанными растрировать размытый заполнитель, даже если изображение уже загружено. Удалив его при загрузке изображения, мы решаем эту проблему. Кроме того, если ваши изображения содержат прозрачность, то это на самом деле не является обязательным, поскольку в противном случае заполнитель будет просвечивать.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<script> document.body.addEventListener( "load", (e) => { if (e.target.tagName != "IMG") { return; } // Remove the blurry placeholder. e.target.style.backgroundImage = "none"; }, /* capture */ true ); </script> |
Инструменты
Это список известных технологий и инструментов, реализующих все эти оптимизации: высокопроизводительный блог одиннадцати.
Автор: Malte Ubl
Источник: www.industrialempathy.com
Редакция: Команда webformyself.