
Загрузка видимых изображений (Lazy Load) на JavaScript
"Lazy Load", "ленивая" или "отложенная загрузка" - особая технология работы с веб-страницами, когда загружаются только те изображения, которые находятся в поле зрения пользователя. Остальные картинки не загружаются до тех пор, пока пользователь не прокрутит страницу до их попадания в видимую область. При большом количестве изображений на странице такой трюк значительно повышает скорость загрузки сайта, а также экономит трафик пользователя и заметно снижает нагрузку на ваш сервер. Особенно это актуально при работе с сайтами на планшетных компьютерах и смартфонах.
Готовых скриптов Lazy Load для разных популярных JavaScript-фреймворков написано уже немало. Мне же, как всегда, захотелось реализовать свой вариант. Да и вам, наверное, будет интересно узнать как это все работает.
Сперва сделаем заготовку 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>
Теперь перейдем к теоретической выкладке. Как работает Lazy Load? После загрузки HTML-содержимого страницы, но до момента ее полной загрузки (все скрипты и изображения), запускается скрипт, который заменяет все изображения в отслеживаемой области на "заглушку" - однопиксельный прозрачный GIF-файл. Чтобы верстка страницы при этом не поплыла, размеры всех оригинальных картинок обязательно должны быть указаны. Данные о ссылках на исходные картинки удобнее всего сохранять прямо в элементе img, добавляя ему наш собственный атрибут lazy. После этого устанавливается обработчик событий на прокрутку окна и изменение размеров. На каждое срабатывание события (пользователь прокручивает страницу), скрипт пробегает по всем картинкам в контейнере, высчитывает их положение относительно верхнего края страницы, и, если они попадают в видимую область, то заменяет атрибут src на сохраненный атрибут lazy. В этом случае картинка будет загружаться с сервера или будет взята из кеша браузера, если он была ранее туда загружена. Для ускорения проверки у отображаемых картинок атрибут lazy можно удалять. Осталось оформить это все в виде скрипта. Нам понадобится вспомогательная функция, которая будет возвращать координаты местоположения элемента на странице относительно верха страницы.
// Вспомогательная функция для определения координат элемента
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};
}
Теперь напишем функцию инициализации. Для повышения быстродействия мы будем обрабатывать не все картинки на странице, а только те, которые находятся в нужном нам контейнере-галерее. Он задается через ID родительского элемента, в нашем случае это "gallery":
// 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();
}
Осталось написать обработчик, который будет показывать картинки в видимой области. Я его подробно прокомментировал, непонятностей быть не должно.
// Обработчик событий прокрутки
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');
}
}
}
}
}
Последний шаг. Осталось все это поместить на нашу страницу. Текст функций для краткости я дублировать не стал, они все описаны выше. Должно получиться примерно следующее:
<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>
Если используются какие-то посторонние фреймворки, то запуск lazy_load() надо забиндить на событие "ondocumentready", то есть когда уже произошла полная загрузка HTML и скриптов, но еще не загружены все картинки. Вешать запуск Lazy Load на событие "onload" бессмысленно, так как при его наступлении все картинки уже загружены, и никакой пользы от использования этой технологии не будет. На индексацию поисковыми системами она также не влияет, ведь в HTML-коде, который "видит" робот-поисковик, прописаны ссылки на оригинальные картинки. Также этот метод будет работать при отключенных скриптах, пользователь просто будет вынужден загрузить сразу все картинки.
Вот такая интересная, а главное полезная технология "отложенной загрузки" изображений. Демонстрационный пример можете посмотреть у меня на сайте. В FireBug наглядно видно, как меняется содержимое страницы по мере ее прокрутки.

Изменение содержимого страницы в FireBug