Привет, Хабр! Представляю вашему вниманию перевод статьи «How to optimize image loading on your website».
Если на сайте много красивых изображений, то это здорово, но они могут значительно ухудшить время загрузки и как результат — пострадает SEO, а многие пользователи будут закрывать сайт еще до того, как он загрузится. Нередко бывает, что несколько мегабайт изображений загружаются просто, чтобы показать слайдер на главной странице.
Представьте, что вы заходите на такой сайт через медленный мобильный интернет, это может занять очень много времени и большинство пользователей в такой ситуации просто закроют ваш сайт еще до его загрузки. Хороший способ протестировать это — воспользоваться возможностью ограничить скорость интернета через Chrome Devtools.
Проблема в том, что часто бывает так, что сам контент уже загружен, а изображения все еще загружаются. В итоге пользователь может увидеть пустое пространство там, где изображения загружаются медленно. Это явно не то, чего вы хотели бы.
В примере ниже я создал простой сайт с фоновым изображением, которое весит 4.8Мб. Как вы можете видеть, DOM загрузился за 1.14 секунды, т.е. фактически пользователь видит содержимое через 1.14 секунды, что довольно неплохо для 3G интернета. Однако, фоновое изображение загружается за 27.32 секунды. За это время пользователь может уже уйти с вашего сайта.
![](https://habrastorage.org/r/w1560/webt/ai/he/nx/aihenxtqzk6volradqbbwp3h7uy.png)
И от этого страдает не только пользовательский опыт. В 2010 Google заявили, что скорость загрузки — это один из факторов в их алгоритме ранжирования и я думаю, что в будущем этот фактор будет становиться все более важным.
Так, как же решить эту проблему? Ну, для начала мы можем просто сжать наше фоновое изображение, используя различные инструменты. Например, TinyPNG, ImageOptimizer или JPEGmini. Это будет легкой победой и уменьшит время загрузки до ~10 секунд. И хотя это выглядит, как огромный шаг в решении, но 10 секунд все еще слишком много.
Следующим шагом может стать загрузка изображения-заглушки перед загрузкой изначального изображения. Заглушка — это версия оригинального изображения, но с низким разрешением. Когда мы создаем такое изображение, то уменьшаем разрешение с 7372x4392 пикселей до 20x11. В итоге размер изображения уменьшается с 4.8Мб до 900 байтов.
![](https://habrastorage.org/r/w1560/webt/pe/dc/j3/pedcj3yrpuo5wzzudyh88wv8g4i.png)
Это позволит уменьшить скорость загрузки с 10 секунд до 550 миллисекунд. Но теперь в качестве фона у нас заблюренное изображение с низким разрешением. Это отличное решение, пока страница загружается первые секунды, но все таки мы хотим показать пользователям оригинальное изображение с высоким разрешением.
Для этого нам придется сначала загрузить изображение с низким разрешением, а уже потом асинхронно в фоне загрузить оригинал с высоким разрешением и, когда версия с высоким разрешением загружена, мы можем поставить ее на место изображения-заглушки. Для этого я использовал нижеприведенный код перед .
Этот код ищет элементы с классом
или
Поскольку скрипт удаляет класс у элемента после загрузки изображения, то при желании мы можем сделать красивую анимацию с помощью CSS. Например, ease-in-out анимация позволит сделать исчезновение заглушки, когда заменяется изображение.
Так чего мы добились? Мы улучшили пользовательский опыт, ускорили загрузку сайта, сделали его более доступным для пользователей без быстрого интернета и возможно улучшили наше ранжирование в Google. Это огромные улучшения для такого маленького изменения.
![](https://habrastorage.org/r/w1560/webt/wm/mc/i2/wmmci2zztcjmxo0yew3-_bnmyku.png)
Как вы можете видеть мы загружаем заглушку за 570 миллисекунд, как только она загрузится пользователь будет видеть заблюренную версию с низким разрешением нашего оригинального изображения, а как только загрузится оригинальное изображение, оно заменит версию с низким разрешением.
Посмотреть рабочий пример можно здесь
Если вы захотите пойти дальше и еще сильнее улучшить загрузку изображений, то возможно вам пригодится ленивая загрузка изображений.
Ленивая загрузка — это техника, когда изображения за пределами видимой области страницы не загружаются, пока изображение не приблизится к краю видимой области.
Ее преимущество в том, что во время первоначальной загрузки будет загружено меньше данных, так как очень часто лишь малая часть изображений отображается в видимой области страницы, а остальные можно загружать по мере того, как пользователь скроллит. Для реализации этого лучше всего подходит Intersection Observer.
Если на сайте много красивых изображений, то это здорово, но они могут значительно ухудшить время загрузки и как результат — пострадает SEO, а многие пользователи будут закрывать сайт еще до того, как он загрузится. Нередко бывает, что несколько мегабайт изображений загружаются просто, чтобы показать слайдер на главной странице.
Представьте, что вы заходите на такой сайт через медленный мобильный интернет, это может занять очень много времени и большинство пользователей в такой ситуации просто закроют ваш сайт еще до его загрузки. Хороший способ протестировать это — воспользоваться возможностью ограничить скорость интернета через Chrome Devtools.
Проблема
Проблема в том, что часто бывает так, что сам контент уже загружен, а изображения все еще загружаются. В итоге пользователь может увидеть пустое пространство там, где изображения загружаются медленно. Это явно не то, чего вы хотели бы.
В примере ниже я создал простой сайт с фоновым изображением, которое весит 4.8Мб. Как вы можете видеть, DOM загрузился за 1.14 секунды, т.е. фактически пользователь видит содержимое через 1.14 секунды, что довольно неплохо для 3G интернета. Однако, фоновое изображение загружается за 27.32 секунды. За это время пользователь может уже уйти с вашего сайта.
![](https://habrastorage.org/webt/ai/he/nx/aihenxtqzk6volradqbbwp3h7uy.png)
И от этого страдает не только пользовательский опыт. В 2010 Google заявили, что скорость загрузки — это один из факторов в их алгоритме ранжирования и я думаю, что в будущем этот фактор будет становиться все более важным.
Решение
Так, как же решить эту проблему? Ну, для начала мы можем просто сжать наше фоновое изображение, используя различные инструменты. Например, TinyPNG, ImageOptimizer или JPEGmini. Это будет легкой победой и уменьшит время загрузки до ~10 секунд. И хотя это выглядит, как огромный шаг в решении, но 10 секунд все еще слишком много.
Следующим шагом может стать загрузка изображения-заглушки перед загрузкой изначального изображения. Заглушка — это версия оригинального изображения, но с низким разрешением. Когда мы создаем такое изображение, то уменьшаем разрешение с 7372x4392 пикселей до 20x11. В итоге размер изображения уменьшается с 4.8Мб до 900 байтов.
![](https://habrastorage.org/webt/pe/dc/j3/pedcj3yrpuo5wzzudyh88wv8g4i.png)
Это позволит уменьшить скорость загрузки с 10 секунд до 550 миллисекунд. Но теперь в качестве фона у нас заблюренное изображение с низким разрешением. Это отличное решение, пока страница загружается первые секунды, но все таки мы хотим показать пользователям оригинальное изображение с высоким разрешением.
Для этого нам придется сначала загрузить изображение с низким разрешением, а уже потом асинхронно в фоне загрузить оригинал с высоким разрешением и, когда версия с высоким разрешением загружена, мы можем поставить ее на место изображения-заглушки. Для этого я использовал нижеприведенный код перед .
(() => {
'use strict';
// Page is loaded
const objects = document.getElementsByClassName('asyncImage');
Array.from(objects).map((item) => {
// Start loading image
const img = new Image();
img.src = item.dataset.src;
// Once image is loaded replace the src of the HTML element
img.onload = () => {
item.classList.remove('asyncImage');
return item.nodeName === 'IMG' ?
item.src = item.dataset.src :
item.style.backgroundImage = `url(${item.dataset.src})`;
};
});
})();
Этот код ищет элементы с классом
asyncImage
, после чего загружает все изображения, указанные в атрибуте data-src
, а как только изображение загрузилось, заменит src
для элемента <img>
, а для остальных элементов установит фоновое изображения через css.<div class="asyncImage" data-src="/images/background.jpg">
...
</div>
или
<img class="asyncImage" src="/images/background-min.jpg" data-src="/images/background.jpg" alt="Beautiful landscape sunrise">
Поскольку скрипт удаляет класс у элемента после загрузки изображения, то при желании мы можем сделать красивую анимацию с помощью CSS. Например, ease-in-out анимация позволит сделать исчезновение заглушки, когда заменяется изображение.
Заключение
Так чего мы добились? Мы улучшили пользовательский опыт, ускорили загрузку сайта, сделали его более доступным для пользователей без быстрого интернета и возможно улучшили наше ранжирование в Google. Это огромные улучшения для такого маленького изменения.
![](https://habrastorage.org/webt/wm/mc/i2/wmmci2zztcjmxo0yew3-_bnmyku.png)
Как вы можете видеть мы загружаем заглушку за 570 миллисекунд, как только она загрузится пользователь будет видеть заблюренную версию с низким разрешением нашего оригинального изображения, а как только загрузится оригинальное изображение, оно заменит версию с низким разрешением.
Посмотреть рабочий пример можно здесь
Ленивая загрузка изображений
Если вы захотите пойти дальше и еще сильнее улучшить загрузку изображений, то возможно вам пригодится ленивая загрузка изображений.
Ленивая загрузка — это техника, когда изображения за пределами видимой области страницы не загружаются, пока изображение не приблизится к краю видимой области.
Ее преимущество в том, что во время первоначальной загрузки будет загружено меньше данных, так как очень часто лишь малая часть изображений отображается в видимой области страницы, а остальные можно загружать по мере того, как пользователь скроллит. Для реализации этого лучше всего подходит Intersection Observer.