- PVSM.RU - https://www.pvsm.ru -
В этой статье я расскажу про 8 методик оптимизации загрузки изображений, которые уменьшают необходимую пропускную способность сети и нагрузку на процессор при выводе на экран. Приведу примеры аннотированного HTML, чтобы вам было легче воспроизвести. Какие-то методики уже давно известны, а какие-то появились относительно недавно. В идеале, ваш любимый механизм публикации веб-документов (например, CMS, генератор статичных сайтов или фреймворк для веб-приложений) должен всё это реализовывать из коробки.
В совокупности методики оптимизируют все элементы Google Core Web Vitals [1] с помощью:
Чтобы увидеть в действии работу всех методик, посмотрите на исходный код загрузки этого изображения:
https://www.industrialempathy.com/img/remote/ZiClJf.jpg
<img loading="lazy" decoding="async" style="background-size: cover; background-image: none;" src="/img/remote/ZiClJf.avif" alt="Sample image illustrating the techniques outlined in this post." width="4032" height="2268">
Это понятная методика позволяет изображению занимать доступное горизонтальное пространство с сохранением соотношения сторон. В 2020-м браузеры научились резервировать корректное количество вертикального пространства под изображение до его загрузки, если в элементе img
указаны атрибуты width
и height
. Это позволяет избежать накопительного сдвига макета.
<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
говорит браузеру не думать о размещении изображения, пока оно не будет готово. У этого подхода несколько достоинств, главное из которых в том, что пока браузер не получит размытое изображение-заглушку или само изображение, он не будет его декодировать, экономя ресурсы процессора.
В более ранней версии статьи объяснялось, как с помощью contain-intrinsic-size
избежать эффекта CLS при использовании content-visibility: auto
. Но в Chromium 88 это больше не нужно в случае с изображениями, для которых указаны width
и height
. По состоянию на 27 января 2021 года content-visibility: auto
ещё не реализован в других браузерных движках [5], вероятно, они последуют примеру Chromium. Так что да, теперь с этим гораздо проще!
<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 [6] — самый свежий графический формат, который получил поддержку в браузерах. Сейчас он поддерживается в Chromium и по флагу в Firefox. Safari с ним пока не работает, но поскольку Apple является участником группы [7], разработавшей формат, в будущем этот браузер тоже должен поддерживать AVIF.
Этот формат примечателен тем, что он значительно превосходит JPEG. И этим выгодно отличается от формата WebP, изображения в котором не всегда меньше JPEG и который может повышать потребление ресурсов из-за отсутствия поддержки прогрессирующей загрузки.
Для реализации прогрессирующего расширения для AVIF можно воспользоваться элементом picture
[8].
Фактически элемент img
вложен в picture
. Это может запутать, потому что img
иногда называют запасным решением для браузеров, не поддерживающих picture
, но по сути этот элемент помогает лишь с выбором src
, а своего макета у него нет. Отрисуется именно элемент img
, к нему вы и будете применять стиль.
До недавнего времени было довольно сложно внедрять на серверной стороне AVIF-изображения, но свежие версии библиотек вроде sharp [9] сильно облегчили эту задачу.
<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
предоставить больше исходных элементов:
<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 изображения хеш количества байтов, которые занимает картинка. В примере выше я сделал это с помощью Z1s3TKV
. При изменении изображения поменяется и URL, а значит вы можете применять бесконечное кеширование картинок. Кеширующие заголовки должны выглядеть так: cache-control: public,max-age=31536000,immutable
.
immutable
— семантически правильное значение cache-control
, но сегодня оно мало поддерживается браузерами (я смотрю на тебя, Chrome). max-age=31536000
— запасной способ кеширования в течение года. public
нужен для того, чтобы ваш CDN кешировала изображение и доставляла его с границы сети. Но этот подход можно использовать только в том случае, если он не нарушает ваших правил соблюдения приватности.
Добавив loading=«lazy»
в элемент img
мы говорим браузеру начать извлекать изображение лишь тогда, когда оно готово быть отрисовано.
<img loading="lazy" … />
Добавив decoding=«async»
в элемент img
мы разрешаем браузеру расшифровывать изображение вне основного потока, чтобы эта процедура не помешала пользователю. Заметных недостатков у этого решения быть не должно, за исключением того, что оно не всегда применима по умолчанию в старых браузерах.
<img decoding="async" … />
Размытая заглушка — это инлайненное изображение, дающее пользователю какое-то представление о полноценной картинке, которая будет позднее загружена, без передачи данных по сети.
https://www.industrialempathy.com/img/blurry.svg [10]
Несколько замечаний по реализации:
background-image
изображения. Эта методика позволяет отказаться от второго HTML-элемента буквально прячет заглушку, когда загружается основное изображение, для этого не нужен JavaScript.<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');
"
…
/>
Браузеры могут быть вынуждены растеризовать размытую заглушку, даже если изображение уже загружено. Проблему можно решить, убрав растеризацию при загрузке. Кроме того, если у вашего изображения есть прозрачные области, то эта оптимизация становится обязательной, иначе сквозь картинку будет просвечивать заглушка.
<sсript>
document.body.addEventListener(
"load",
(e) => {
if (e.target.tagName != "IMG") {
return;
}
// Remove the blurry placeholder.
e.target.style.backgroundImage = "none";
},
/* capture */ true
);
</sсript>
Полезный инструмент, реализующий все описанные оптимизации: eleventy-high-performance-blog [11]
Автор: Макс
Источник [12]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/brauzery/361797
Ссылки в тексте:
[1] Google Core Web Vitals: https://web.dev/vitals/
[2] Largest Contentful Paint (LCP): https://web.dev/lcp/
[3] Cumulative Layout Shift (CLS): https://web.dev/cls/
[4] First Input Delay (FID): https://web.dev/fid/
[5] content-visibility: auto
ещё не реализован в других браузерных движках: https://caniuse.com/?search=content-visibility
[6] AVIF: https://jakearchibald.com/2020/avif-has-landed/
[7] группы: http://aomedia.org/
[8] элементом picture
: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture
[9] sharp: https://github.com/lovell/sharp
[10] https://www.industrialempathy.com/img/blurry.svg: https://www.industrialempathy.com/img/blurry.svg
[11] eleventy-high-performance-blog: https://github.com/google/eleventy-high-performance-blog
[12] Источник: https://habr.com/ru/post/543434/?utm_source=habrahabr&utm_medium=rss&utm_campaign=543434
Нажмите здесь для печати.