
Загрузка видимых изображений (Lazy Load) на JavaScript

Загрузка видимых изображений (Lazy Load) на JavaScript
"Lazy Load", "ленивая" или "отложенная загрузка" - особая технология работы с веб-страницами, когда загружаются только те изображения, которые находятся в поле зрения пользователя. Остальные картинки не загружаются до тех пор, пока пользователь не прокрутит страницу до их попадания в видимую область. При большом количестве изображений на странице такой трюк значительно повышает скорость загрузки сайта, а также экономит трафик пользователя и заметно снижает нагрузку на ваш сервер. Особенно это актуально при работе с сайтами на планшетных компьютерах и смартфонах.
Готовых скриптов Lazy Load для разных популярных JavaScript-фреймворков написано уже немало. Мне же, как всегда, захотелось реализовать свой вариант. Да и вам, наверное, будет интересно узнать как это все работает.
Сперва сделаем заготовку HTML-страницы. Это будет контейнер галереи, в котором будут размещены несколько картинок. Ничего сложного, самая обычная верстка:
Code (HTML) : Убрать нумерацию
- <div id="gallery">
- <img src="/images/image01.jpg" width="600" height="450" alt="Фото 1">
- <img src="/images/image02.jpg" width="600" height="450" alt="Фото 2">
- <img src="/images/image03.jpg" width="600" height="450" alt="Фото 3">
- <img src="/images/image04.jpg" width="600" height="450" alt="Фото 4">
- <img src="/images/image05.jpg" width="600" height="450" alt="Фото 5">
- <img src="/images/image06.jpg" width="600" height="450" alt="Фото 6">
- <img src="/images/image07.jpg" width="600" height="450" alt="Фото 7">
- <img src="/images/image08.jpg" width="600" height="450" alt="Фото 8">
- <img src="/images/image09.jpg" width="600" height="450" alt="Фото 9">
- <img src="/images/image10.jpg" width="600" height="450" alt="Фото 10">
- <img src="/images/image11.jpg" width="600" height="450" alt="Фото 11">
- <img src="/images/image12.jpg" width="600" height="450" alt="Фото 12">
- </div>
Code (JavaScript) : Убрать нумерацию
- // Вспомогательная функция для определения координат элемента
- function lazy_get_position(element) {
- var offsetLeft=0;
- var offsetTop=0;
- do {
- offsetLeft+=element.offsetLeft;
- offsetTop+=element.offsetTop;
- }
- while (element=element.offsetParent);
- return {x:offsetLeft, y:offsetTop};
- }
Code (JavaScript) : Убрать нумерацию
- // ID родительского элемента
- var lazy_parent_id='gallery';
- function lazy_load() {
- // Картинка-заместитель
- var lazy_replacer='dot.gif';
- var container=document.getElementById(lazy_parent_id);
- if (container) {
- var im=container.getElementsByTagName('img');
- // Сохранить адрес исходной картинки и заменить его на прозрачный GIF
- for (var i=0; i<im.length; i++) {
- var el=im[i];
- if (el.src) {
- el.setAttribute('lazy',el.src);
- el.lazy=el.src;
- el.src=lazy_replacer;
- }
- }
- }
- // Установить обработчики событий окна
- window.onscroll = lazy_load_proc;
- window.onresize = lazy_load_proc;
- // Сразу же показать картинки в видимой области
- lazy_load_proc();
- }
Code (JavaScript) : Убрать нумерацию
- // Обработчик событий прокрутки
- function lazy_load_proc() {
- var doc = document.documentElement;
- var body = document.body;
- // Получить размеры видимой области страницы (кроссбраузерно)
- if (typeof(window.innerWidth) == 'number') {
- my_width = window.innerWidth;
- my_height = window.innerHeight;
- }
- else if (doc && (doc.clientWidth || doc.clientHeight)) {
- my_width = doc.clientWidth;
- my_height = doc.clientHeight;
- }
- else if (body && (body.clientWidth || body.clientHeight)) {
- my_width = body.clientWidth;
- my_height = body.clientHeight;
- }
- // Получить смещение страницы относительно ее верха
- if (doc.scrollTop) { dy=doc.scrollTop; } else { dy=body.scrollTop; }
- // Обработка всех картинок в контейнере
- var container=document.getElementById(lazy_parent_id);
- if (container) {
- var im=container.getElementsByTagName('img');
- for (var i=0; i<im.length; i++) {
- var el=im[i];
- // Если атрибут lazy есть, то обработать картинку
- if (el.lazy) {
- // Получить координаты картинки от верха страницы
- var coord=lazy_get_position(el);
- // Если картинка попала в видимую область, то показать ее.
- // Плюс берется запас в 100 пикселов для более плавной подгрузки
- if (coord.y>(dy-my_height-100) && coord.y<(dy+my_height+100)) {
- // Прописать адрес исходной картинки и убрать атрибут lazy
- el.src=el.lazy;
- el.setAttribute('src',el.lazy);
- el.lazy='';
- el.removeAttribute('lazy');
- }
- }
- }
- }
- }
Code (HTML) : Убрать нумерацию
- <script type="text/javascript">
- // ID родительского элемента
- var lazy_parent_id='gallery';
- function lazy_load() { ... }
- function lazy_load_proc() { ... }
- function lazy_get_position(element) { ... }
- </script>
- <div id="gallery">
- <img src="/images/image01.jpg" width="600" height="450" alt="Фото 1">
- <img src="/images/image02.jpg" width="600" height="450" alt="Фото 2">
- <img src="/images/image03.jpg" width="600" height="450" alt="Фото 3">
- <img src="/images/image04.jpg" width="600" height="450" alt="Фото 4">
- <img src="/images/image05.jpg" width="600" height="450" alt="Фото 5">
- <img src="/images/image06.jpg" width="600" height="450" alt="Фото 6">
- <img src="/images/image07.jpg" width="600" height="450" alt="Фото 7">
- <img src="/images/image08.jpg" width="600" height="450" alt="Фото 8">
- <img src="/images/image09.jpg" width="600" height="450" alt="Фото 9">
- <img src="/images/image10.jpg" width="600" height="450" alt="Фото 10">
- <img src="/images/image11.jpg" width="600" height="450" alt="Фото 11">
- <img src="/images/image12.jpg" width="600" height="450" alt="Фото 12">
- </div>
- <script type="text/javascript">
- // Инициализировать скрипт
- lazy_load();
- </script>
Вот такая интересная, а главное полезная технология "отложенной загрузки" изображений. Демонстрационный пример можете посмотреть у меня на сайте. В FireBug наглядно видно, как меняется содержимое страницы по мере ее прокрутки.

Изменение содержимого страницы в FireBug
UPD. После обсуждения скрипта был выявлен его существенный недостаток. Стационарные браузеры все равно отправляют запросы на сервер и загружают все картинки, даже если они были скрыты и/или ссылки на них была заменены скриптом. Браузеры на мобильных устройствах ведут себя более экономно к сетевым ресурсам, и скрипт Lazy Load там отрабатывает как задумано. Есть несколько способов решения.
Первый способ. Можно сразу же прописать в HTML-странице вместо ссылок на картинки ссылку на картинку-заместитель, а правильные ссылки разместить в атрибуте "lazy". То есть заранее подготовить страницу к "ленивой загрузке" еще на этапе ее формирования на стороне сервера. Этот способ часто используют крупные интернет-магазины на страницах со списками товаров. Плюс тут один, но большой. Страница будет грузиться мгновенно, ведь по сути на ней будет только одна картинка-заместитель. Но есть и минусы, и они тоже существенные. Такая замена гарантированно нарушит индексацию картинок на сайте поисковыми роботами, потому что реальных ссылок на картинки в тегах не будет, а скрипты роботами не выполняются. Также, если у посетителя сайта отключены скрипты в браузере, то никаких картинок он не увидит.
Второй способ. После формирования DOM-дерева (загружены скрипты и HTML страницы) и после запуска скрипта Lazy Load можно принудительно останавливать дальнейшую загрузку страницы. Делается это примерно так:
Code (JavaScript) : Убрать нумерацию
- try {
- // Остановить загрузку страницы для Firefox, Chrome...
- window.stop();
- }
- catch(e) {
- try {
- // Остановить загрузку страницы для Internet Explorer
- document.execCommand('stop');
- }
- catch(e) {
- // Фокус не удался, функция в браузере не поддерживается
- }
- }
UPD2. Современные браузеры поддерживают для изображений атрибут loading="lazy", но его поддержка более старыми браузерами оставляет желать лучшего. Зато использование этого атрибута решает задачу отложенной загрузки изображений наиболее эффективно.
Как видите, единственно правильного и красивого решения нет, в любом случае приходится чем-то жертвовать. Выбор решения зависит от поставленной задачи.
Просмотров: 16727 | Комментариев: 12
Метки: JavaScript, оформление сайта

Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье

Олег
(09.04.2016 в 12:14):
Здравствуйте! Подскажите, пожалуйста, как заставить подгружаться не только изображения, но и iframe?
Такая строчка в скрипте не помогла
var im=container.getElementsByTagName('iframe');
Такая строчка в скрипте не помогла
var im=container.getElementsByTagName('iframe');

Max
(31.01.2014 в 21:41):
Да замечу почему на планшете грузятся "по другому".
У разных браузеров разный механизм обработки запросов.
В Firefox - запросы к серверу идут в любом случае если стоит путь.
У разных браузеров разный механизм обработки запросов.
В Firefox - запросы к серверу идут в любом случае если стоит путь.

ManHunter
(29.01.2014 в 14:20):
Дополнил статью возможными решениями. Спасибо!

Max
(29.01.2014 в 14:18):
Вот видите, я тоже думал ваш скрипт "панацея" уже обрадовался, но по логике понял что не получиться, проверил - точно, запросы идут.
Тогда лучше использовать готовый скрипт http://www.appelsiini.net/projects/lazyload
Так что я тоже огорчился, но так и предполагал, думаю в http://www.appelsiini.net/projects/lazyload не дураки делали, тоже хотели идеально сделать чтобы и поисковики видели и т.п. Но... не получиться по тех. причинам
;(
Тогда лучше использовать готовый скрипт http://www.appelsiini.net/projects/lazyload
Так что я тоже огорчился, но так и предполагал, думаю в http://www.appelsiini.net/projects/lazyload не дураки делали, тоже хотели идеально сделать чтобы и поисковики видели и т.п. Но... не получиться по тех. причинам
;(

ManHunter
(29.01.2014 в 13:34):
Действительно на стационарном компе грузится все, хоть и в фоне. На планшете с мобильного интернета картинки грузятся только при прокрутке.
Единственное решение я уже указывал - на этапе формирования страницы проставлять всем картинкам src=dot.gif, а при отображении подменять на правильный src. При этом обломятся поисковики картинок и пользователи с отключенными скриптами.
Как еще один вариант можно принудительно остановить загрузку страницы по готовности DOM через window.stop() для браузеров и document.execCommand('stop') для некоторых IE. Программный аналог кнопки Стоп в браузере.
Единственное решение я уже указывал - на этапе формирования страницы проставлять всем картинкам src=dot.gif, а при отображении подменять на правильный src. При этом обломятся поисковики картинок и пользователи с отключенными скриптами.
Как еще один вариант можно принудительно остановить загрузку страницы по готовности DOM через window.stop() для браузеров и document.execCommand('stop') для некоторых IE. Программный аналог кнопки Стоп в браузере.

Max
(29.01.2014 в 05:45):
Не будет он выполнять свое прямое предназначение.
Если в src стоит путь после формирования DOM - будет сформирован и отправлен запрос.
Т.е. запросов к серверу будет в два раза больше.
Если в src стоит путь после формирования DOM - будет сформирован и отправлен запрос.
Т.е. запросов к серверу будет в два раза больше.

Михаил
(02.11.2012 в 12:24):
да, действительно, только в моем случае скрипт будет постоянно подгружать превьюшки, а листалка будет брать полновесные картинки, спасибо за разьяснения, и за скрипт

ManHunter
(02.11.2012 в 11:48):
Берешь и допиливаешь листалку, чтобы она проверяла наличие атрибута lazy и работала аналогично lazyload. И вообще, для галерей всегда делается маленькая легкая превьюшка, которая является _ссылкой_ на полный вариант картинки. Именно эти ссылки и должна обрабатывать листалка, и никак иначе. А этот скрипт заточен на полновесные картинки.

Михаил
(02.11.2012 в 11:42):
Здравствуйте, а что если изображение увеличивается при нажатии, и в увеличеном виде есть пролистывание изображений, берутся все картинки галереи, то пролистаются только изображения которые находятся в видимой области, а дальше будет листаться однопиксельный прозрачный GIF-файл?

Александр
(14.08.2012 в 14:52):
Всегда интересно узнать что-то новое. Спасибо.

Игорь
(12.08.2012 в 05:25):
Благодарю за вашу статью, применил вашу разработку на своем ресурсе:)

Добавить комментарий
Заполните форму для добавления комментария

Вы тут указываете явные размеры картинок.