Ускорить сайт с множеством картинок: руководство по отложенной загрузке изображений Статьи редакции

Перевод материала сооснователя сервиса для оптимизации изображений ImageKit Рахула Нанвани.

Изображения важны для каждого сайта и приложения. Невозможно представить себе сайт без рекламного баннера, изображения продукта или логотипа.

Но изображения часто много весят, и это в первую очередь влияет на размер страницы. Согласно данным сайта HTTP Archive, средний вес страницы на компьютере составляет 1511 КБ. Изображения занимают почти 650 КБ, что примерно 45% от общего числа.

Теперь важно сделать быструю загрузку страницы с изображениями. В этом материале расскажу об отложенной загрузке — методе, который поможет сократить время загрузки страницы и уменьшить её размер, не жертвуя картинками.

Основные возможности — вкратце

Вот видео, демонстрирующее принцип работы. Обратите внимание, как при прокрутке страницы серый плейсхолдер заменяет изображение.

Что такое отложенная загрузка

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

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

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

Инструменты

Основная идея проста — отложить загрузку всего, что не нужно пользователю прямо сейчас. К любому изображению, которое пользователь не видит изначально, можно применить этот метод.

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

С помощью расширения Lighthouse для браузера Google Chrome можно узнать, какие изображения подходят для отложенной загрузки и сколько трафика можно сэкономить. В расширении есть раздел, посвящённый закадровым изображениям.

Также можно использовать анализатор сайтов от ImageKit, чтобы определить, использует сайт отложенную загрузку или нет.

Способы реализации

Изображения на странице можно загружать двумя способами — с помощью тега <img> или с помощью CSS-свойства «background», которое позволяет установить одновременно несколько характеристик фона. Сначала рассмотрим более распространённый тег <img>, а затем перейдём к фоновым изображениям CSS.

Тег <img>

Отложенную загрузку изображений можно разделить на два этапа.

Шаг первый — предотвратить изначальную загрузку изображения. Для изображений, загруженных с помощью тега <img />, браузер использует атрибут тега «src» для запуска загрузки изображения. Не имеет значения, первое это или тысячное изображение в HTML и закадровое ли оно. Если браузер получит атрибут «src», это вызовет загрузку изображения.

Чтобы загрузить изображение через отложенную загрузку, нужно поместить URL-адрес изображения в атрибут «src». Допустим, указываем URL-адрес изображения в атрибуте «data-src» тега «image». Теперь, когда «src» пуст, браузер не начинает загрузку изображения.

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

Загрузка изображений с помощью событий JavaScript

В этом методе используем отслеживание событий прокрутки (scroll), изменения размера (resize), смены ориентации (orientationChange) в браузере.

Когда происходит одно из этих событий, находим все изображения на странице, которые ещё не загружены. Проверяем, какие из них теперь находятся в окне просмотра. Это можно определить с помощью свойств «offset top», «scroll top» и «window height».

Если изображение вошло в окно просмотра, берём URL из атрибута «data-src» и помещаем его в атрибут «src». Это запускает загрузку изображения. Также удаляем класс «lazy», определяющий изображения, которые будут загружаться позже. После загрузки всех изображений удаляем инструменты для отслеживания событий.

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

Первые три изображения в примере загружаются заранее. URL-адрес присутствует непосредственно в атрибуте «src» вместо атрибута «data-src». Это необходимо для хорошего пользовательского опыта. Поскольку эти изображения находятся в верхней части страницы, их следует сделать видимыми как можно скорее. Мы не должны ждать события или выполнения JavaScript, чтобы загрузить их.

Загрузка изображений с помощью Intersection Observer API

Intersection Observer API — относительно новый API в браузерах. Он определяет, когда элемент входит в окно просмотра, и начинает действовать. В предыдущем методе приходилось связывать события, учитывать производительность и подсчитывать время появления элемента в окне просмотра.

Intersection Observer API делает процесс проще, помогает избежать вычислений и обеспечивает хорошую производительность.

Ниже — пример использования Intersection Observer API для отложенной загрузки изображений.

Как только API обнаруживает, что элемент вошёл в окно просмотра, используя свойство «isIntersecting», выбираем URL из атрибута «data-src» и перемещаем его в атрибут «src», чтобы запустить отложенную загрузку. Как только это будет сделано, удаляем класс «lazy» из изображения, а также удаляем оттуда обсервер.

Если вы сравните время загрузки изображения двух методов — с отслеживанием событий и Intersection Observer API, — то обнаружите, что с помощью Intersection Observer API загрузка изображения запускается гораздо быстрее, и сайт уже не смотрится «вялым» при скроллинге.

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

Однако, как и всё новое, поддержка Intersection Observer API доступна не во всех браузерах. Таким образом, приходится возвращаться к методу отслеживания событий в браузерах, где Intersection Observer API не поддерживается. Учли этот момент в приведённом выше примере.

Отложенная загрузка фоновых изображений CSS

После тегов <img /> фоновые изображения являются наиболее распространённым способом загрузки изображений для страниц. Для тегов <img /> в браузере простой подход — если URL-адрес изображения доступен, то можно его загрузить.

С фоновыми изображениями CSS не всё так просто. Чтобы загрузить фоновые изображения CSS, браузер должен создать дерево DOM (объектная модель документа), а также дерево CSSOM (объектная модель CSS), чтобы решить, применяется ли стиль CSS к узлу DOM в текущем документе.

Если правило CSS, определяющее фоновое изображение, не применяется к элементу в документе, то браузер не загружает фоновое изображение. Если применяется — загружает.

Поначалу это может показаться сложным, но такой же принцип лежит в основе техники отложенной загрузки фоновых изображений. Так мы обманываем браузер, не применяя свойство CSS «background-image» к элементу, пока этот элемент не попадёт в окно просмотра. Ниже рабочий пример отложенной загрузки фонового изображения CSS.

Здесь следует отметить, что код JavaScript для отложенной загрузки остаётся прежним. Мы используем Intersection Observer API, возвращаясь затем к отслеживанию событий. Хитрость заключается в CSS.

Элемент с идентификатором «bg-image» имеет заданное свойство «background-image» в CSS. Однако когда класс «lazy» добавляется к этому элементу, в CSS мы переопределяем свойство «background-image» и меняем его на значение «none».

Так как по правилам комбинация «bg-image» с «.lazy» имеет более высокое предпочтение в CSS, чем просто «bg-image», браузер применяет свойство «background-image: none» к элементу изначально.

Когда прокручиваем страницу вниз, the Intersection Observer (или отслеживание событий) определяет, что изображение находится в окне просмотра, и удаляет класс «lazy». Это изменяет применяемый сейчас CSS и применяет свойство «background-image» к элементу, начавшему загрузку фонового изображения.

Улучшить пользовательский опыт

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

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

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

1. Правильный дизайн плейсхолдеров

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

Мы использовали подобный плейсхолдер в нашем примере — везде он выкрашен в сплошной светло-серый цвет. Тем не менее можно сделать лучше. Ниже — примеры использования более удачных вариантов плейсхолдеров.

Плейсхолдер доминирующего цвета

Этот метод давно используется для результатов поиска изображений в Google и Pinterest.

Пример с Manu ninja

Может показаться, что это сложно реализовать. Но есть простой способ — сначала уменьшить изображение до пикселя 1×1, а затем масштабировать его до размера плейсхолдера — грубое приближение, но оно помогает легко получить один доминирующий цвет. Используя ImageKit, плейсхолдер доминирующего цвета можно получить с помощью цепного преобразования, как показано ниже.

Размер изображения-плейсхолдера составляет всего 661 байт, по сравнению с исходным изображением, которое имеет размер 12 700 байт — в 19 раз меньше. И это обеспечивает более приятный опыт перехода от плейсхолдера к изображению.

Рабочий пример и код для использования плейсхолдера доминирующего цвета — по ссылке.

Плейсхолдер низкого качества (LQIP)

Есть способ расширить приведённую выше идею использования плейсхолдера доминирующего цвета. Вместо одного цвета можно использовать некачественную размытую версию исходного изображения.

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

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

Рабочий пример и код для использования техники LQIP — по ссылке.

2. Добавление буферного времени

Часто пользователи быстро прокручивают страницу, и для загрузки и отображения картинки на экране требуется некоторое время. Событие «load image» может сработать с задержкой, как и плейсхолдеры. Это плохо влияет на пользовательский опыт.

Решение

Вместо того чтобы загружать изображения только тогда, когда они точно входят в окно просмотра, загрузите картинки, когда они, например, в 500 px от края.

С помощью Intersection Observer API можно использовать параметр «`root`» вместе с параметром «rootMargin» (работает по стандартному принципу поля CSS), чтобы увеличить границы рамки.

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

В этом примере используется пороговое значение 500 px для загрузки изображений.

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

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

Если не заметили ранее, во всех примерах третье изображение (image3.jpg) всегда загружается сразу, даже если оно находится вне области просмотра. Это было сделано в соответствии с тем же принципом: выполнить загрузку немного заранее для лучшего пользовательского опыта.

3. Как избежать смещения содержимого

При отсутствии изображения браузер не знает размеров содержимого, которое должно отображаться в пределах контейнера. Если не задать его с помощью CSS, конечный контейнер не будет иметь размеров, то есть его размеры будут равны 0 x 0 px.

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

Как показано в этом материале Smashing Magazine, смещение контента и видео — довольно неприятный опыт для пользователя.

Решение

Этого можно избежать, указав высоту и (или) ширину для конечного контейнера, чтобы браузер мог нарисовать контейнер изображения с известной высотой и шириной.

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

4. Не стоит применять отложенную загрузку для всех изображений

Ещё одна ошибка, которую часто совершают разработчики, — загружают все изображения на страницу с помощью отложенной загрузки. Это может сократить время на начальную загрузку страницы, но также приведёт к плохому пользовательскому опыту, поскольку многие изображения даже в верхней части страницы не будут отображаться до тех пор, пока JavaScript не будет выполнен.

Можно следовать общим принципам, чтобы определить, какие изображения должны быть загружены после.

  • Любое изображение, которое присутствует в окне просмотра или в начале страницы, не должно загружаться с помощью отложенной загрузки. Это касается любого изображения-заголовка, рекламных баннеров, логотипов. Пользователь должен видеть их, как только страница загрузится. Помните, что мобильные и десктопные устройства будут иметь разные размеры экрана и, следовательно, разное количество изображений, которые будут видны на экране изначально. Таким образом, необходимо учитывать тип устройства, чтобы решить, какие изображения загружать изначально, а какие нет.
  • Любое изображение, которое частично видно в окне просмотра, не должно загружаться с помощью отложенной загрузки. Это происходит по принципу, который обсуждался выше, — загружать чуть заранее. Любое изображение, находящееся, допустим, в 500 px от области просмотра, может быть загружено заранее.
  • Если страница не длинная, её можно пролистать за несколько движений. Или если за пределами окна просмотра меньше пяти изображений, то отложенную загрузку можно не использовать. Это не принесёт существенной выгоды пользователю с точки зрения производительности. Дополнительный JavaScript, который вы загружаете на страницу, чтобы включить отложенную загрузку, компенсирует выигрыш от отложенной загрузки такого небольшого количества изображений.

Популярные JavaScript-библиотеки

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

  • yall.js (Yet Another Lazy Loader) — использует Intersection Observer API и возвращается к отложенной загрузке на основе событий. Поддерживает все основные типы элементов HTML, но не «background-image». Также работает на Internet Explorer 11 и старших версиях.
  • lazysizes — библиотека с обширной функциональностью. Поддерживает адаптивные изображения «srcset» и атрибут «sizes». Высокая эффективность даже без Intersection Observer API.
  • jQuery Lazy — простая, основанная на jQuery, библиотека отложенной загрузки.
  • WeltPixel Lazy Loading Enhanced — расширение для Magento 2 для отложенной загрузки изображений.
  • Magento Lazy Image Loader — расширение для Magento 1.x для отложенной загрузки изображений.
  • Shopify Lazy Image Plugin — расширение для Shopify для отложенной загрузки изображений. Платная.
  • WordPress A3 Lazy Load — плагин отложенной загрузки изображений для WordPress.

Как проверить, всё ли работает

Самый простой способ — открыть инструменты разработчика в браузере Chrome. Перейдите на вкладку «Сеть» → «Изображения». Здесь при первом обновлении страницы должны загружаться только те изображения, которые должны присутствовать на странице изначально.

Затем, когда вы начинаете прокручивать страницу вниз, другие запросы загрузки изображений будут запускаться и загружаться. Также можно заметить тайминги для загрузки изображения. Это поможет определить проблемы с загрузкой изображений, если таковые имеются, или проблемы с запуском загрузки изображений.

Другой способ — запустить расширение Lighthouse от Google Chrome на странице после внесения изменений и найти предложения в разделе Offscreen images.

Если не работает

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

Или можно использовать тег <noscript>, чтобы создать удобный интерфейс для этих пользователей. В треде Stack Overflow рассматриваются проблемы этого тега. Материал будет полезен для всех, чья целевая аудитория — такие пользователи.

0
28 комментариев
Написать комментарий...
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
Nivenor

Ничего-то вы не понимаете. Сегодня нельзя просто так взять и сверстать страничку, как это делалось 15 лет назад - чтобы она просто тупо работала, быстро и надёжно. За это никто вам денег сегодня не заплатит. И на работу вас не возьмёт. А вот когда вы научитесь обклеивать эту несчастную страничку реактами, ангулярами, анимациями, шрифтами, параллаксами и отложенными загрузками, как ёлку мишурой, и превращать её в прогрессивное и реактивное веб-приложение, способное вызвать у пользователя вопрос "Да что там, опять майнер, что ли?" - вот тогда вы профессионал, тогда у вас есть з/п и вам есть что написать в резюме.

Ответить
Развернуть ветку
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
Mark Rapida Gromov

все куда сложнее

Ответить
Развернуть ветку
Pavel Zakharov

Медленный интернет всё ещё существует, когда ты с лагающего 3g по 30-40 секунд открываешь страницу с кучей изображений но с первого абзаца текста понимаешь, что это не то, что ты искал (повторить 2-5 раз) - это бесит гораздо сильнее.

Ответить
Развернуть ветку
Roman Pan

Как роботы видят сайт?

Ответить
Развернуть ветку
Кибердиван

Плохо. Особенно картинки. Постоянно путают светофоры и витрины...

Ответить
Развернуть ветку
Dmitry Ulitin

Гугл так же как пользователь в браузере

Ответить
Развернуть ветку
Рустам Фатов

если у пользователя js отключен, ничего не загрузится, лучше проверенного имэгэ ничего нет еще) кстати были помню ролловеры какие то, загружают сперва изображения с низким качеством, затем заменяют его на высокое, когда скорость интернета была низкой... сейчас когда 4g и технологии высокоскоростного интернета развиваются, тема оптимизации изображений уходит на второй план, ест-но если это фотосток какой нить, то тогда да важно

Ответить
Развернуть ветку
Денис Демидов

Сейчас кто-то отключает js? Какие сайты после этого работают?

Ответить
Развернуть ветку
Рустам Фатов

параноики (могут шпионить через js) и кого бесит всплывающая реклама и прочие, да пару процентов а то и все 5 может набраться юзеров с отключенным js

Ответить
Развернуть ветку
Mark Rapida Gromov

это такой пласт населения, который обычно не приносит выгоды, так что не страшно

Ответить
Развернуть ветку
Михаил Затолокин

Скажите это гугл спидтесту)

Ответить
Развернуть ветку
Мсье Риддлер

а если морда написана на реакте, вью или ангуляре - вообще весь сайт не загрузится.

Ответить
Развернуть ветку
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
Руслан Яцукевич

А можно делать сайты на Битрикс, использовать Bitrix CDN, который сжимает картинки, снижает нагрузку на сервер и доставляет картикни до клиента максимально быстро. В том числе используя ряд технологий описанных в статье.
Обращайтесь. Помогу.

Ответить
Развернуть ветку
Ilya Aparin

О, Битрикс евангелисты подъехали. Для таких тривиальных задач вовсе не обязательно использовать нонфри Фреймворк.

Ответить
Развернуть ветку
Руслан Яцукевич

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

Ответить
Развернуть ветку
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
Andrey Korobeynikov

Если в теге <img> мы не передаём src, то наши картинки не появятся в картинках поисковых систем. Как быть с этим, для продвижения это плохо.

Ответить
Развернуть ветку
Mark Rapida Gromov

для роботов можно отдавать обычную картинку в src

Ответить
Развернуть ветку
Денис Малышев

https://squoosh.app/ сжимаю в нем иногда большие фотки до 60%, в основном жму до 75. На выходе мизерный размер и PageSpeed Insights доволен. Зачем париться и извращаться если у тебя обычный сайт, а не сплошная лента в 100500 фоток?

Ответить
Развернуть ветку
Roman Goncharenko

а как бы его автоматизировать? чтобы не руками свкушить, а через cli?

Ответить
Развернуть ветку
Алексей из LOADING.express

Всё верно. Отложенная подгрузка это только один из инструментов, которые надо использовать в ускорении сайтов. Вот мы тут статью про это целую тоже выпустили и добрые мальчики ее заминусовали, потому что 30 секунд загрузки, говорят, это фигня. Подождут типа. https://vc.ru/marketing/61748-medlennyy-sayt-ubiyca-vashih-prodazh

Ответить
Развернуть ветку
Влад Комарик

Скажите пожалуйсто, сделал как все описано было выше по первому примеру через яву, но на мобильных устройствах не работает, картинки не загружаются. пробовал на планшете с я.браузером и Хром - история одинаковая. Почему? Помогите разобраться. Вот, на всякий случай, адрес страницы для примера: https://avtoyoutube.ru/znak-podema-i-spuska-chto-znachat.php

Ответить
Развернуть ветку
Влад Комарик

просьба не пинать за активную ссылку, я не знал как ее сделать не активной.

Ответить
Развернуть ветку
SMik

Большое спасибо за статью! В разделе "Загрузка изображений с помощью событий JavaScript" нужно код немного поправить, иначе, при каждом скроле будет перезагружаться картинка. Не смотря на то, что в вёрстке убрали класс lazy у img. Особенно весело смотрится, когда lazy у анимированного gif (гиф сначала начинает воспроизводиться при каждом скроле). В общем, чтобы всё правильно работало, нужно
"var lazyloadImages = document.querySelectorAll("img.lazy");"
объявлять ВНУТРИ функции "function lazyload () {" :
<code>
function lazyload () {
var lazyloadImages = document.querySelectorAll("img.lazy");
</code>

Ответить
Развернуть ветку
25 комментариев
Раскрывать всегда