Управляем загрузкой изображений

04.05.2019
Для чего нам нужна предварительная загрузка изображений? Чаще всего мы используем её для качественно прорисовки интерфейсов, элементов управления сайта.
Пример:
Есть скрипт галереи или текстовые блоки с возможностью перемещения (туда/сюда). За управление перемещением отвечают графические стрелки. При наведении на стрелку её изображение заменяется на другое.
Что делает браузер при наведении? Он отправляет запрос на изображение к серверу. Даже при очень быстром ответе будет замечен эффект «подмаргивания». Если выполнить предварительную загрузку изображений - этого не произойдёт.
Применение
В современной вёрстке этот подход используется редко. Гораздо предпочтительнее использовать CSS Sprites. Но, если нет такой возможности и Вам действительно это надо - добро пожаловать под кат.

Var imgPath = "/tpl/images/"; // путь к каталогу с изображениями // список изображений var preloadImagesList = Array("about_hover.jpg", "news_hover.jpg", "photo_hover.jpg", "video_hover.jpg", "contacts_hover.jpg");// /*******************************/ // функция предварительной загрузки function preloadImages(images){ for(var i = 0; i < images.length; i++){ var image = images[i]; $("").attr("src", imgPath + image); }//for }//preloadImages /*******************************/ //вызов функции $().ready(function(){ preloadImages(preloadImagesList); })

Для игры нужно подгрузить заранее в районе 12 изображений, причем эти изображения могут варьироваться от случая к случаю. То есть сейчас мне нужно подгрузить одни 12 изображений (SVG), а завтра нужно будет другие 12. Поэтому вариант помещения их в

не подходит, ибо в этом случае придется постоянно грузить все изображения, а понадобятся мне из них всего 12. Поэтому было решено подгружать их средствами JavaScript перед началом игры. Для этого я реализовал небольшой класс "AssetsPreloader", который, пока что, имеет единственный метод "preload", который принимает массив из объектов вида {src: "ссылка", id: "id"} и подгружает необходимые изображения путем простого создания экземпляра класса Image() (нативный).

Class AssetsPreloader { static preload(arr) { arr.map((a) => { let img = new Image(); img.src = a.src; img.id = a.id; (this.assets = this.assets || ).push(img); }); } }

Все подгруженные изображения в итоге попадают в статическое свойство assets этого класса.

Следующим в коде идет отрисовка первого кадра игры, где эти изображения уже используются. И, в общем-то, проблема в том, что отрисовка не происходит. До нее выполнение кода доходит, это я проверял, и после нее код выполняется, но сами изображения не отрисовываются. Насколько я понимаю, происходит это потому, что изображения не успевают загрузиться (даже несмотря на то, что загрузка их происходит с диска). Однако, если запросить отрисовку первого кадра прямо из консоли браузера, то все работает как надо и кадр рисуется нормально.

Весь код в общем и целом выглядит примерно так:

Class AssetsPreloader { static preload(arr) { arr.map((a) => { let img = new Image(); img.src = a.src; img.id = a.id; (this.assets = this.assets || ).push(img); this.done = true; }); } } AssetsPreloader.preload([ {src: "images/image.svg", id: "id_of_image"}, ... ]); // ... GAME.field.draw();

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

Прошу помощи. Интересует не только как, но и как наиболее правильно (best-practice, все такое).

P.S. Файл скрипта подключен к странице с атрибутом defer . При использовании, например, async , отрисовка либо происходит, либо нет (отчего зависит - не могу сказать). А вешать в сам код обработчики проверки загрузки страницы, готовности DOM или что-то в этом роде не хочу.

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

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

В нём есть базовый функционал, позволяющий выполнять две основные функции: загружать изображения и вызывать после этого коллбэк. Но так же есть и свои фичи. Он может загружать картинки по очереди в том порядке, в котором они были помещены в массив. Не только по одному, а по два-три-N. А на каждую итерацию загрузки может выполнять коллбэк. Но и это ещё не всё: после загрузки последнего изображения выполнится финальный коллбэк, говорящий о том, что все изображения загружены.

Использование

Существует два варианта использования jQuery.preload.
Первый — передавать адрес(а) изображений:

$.preload(images, , );

  • images
    Адрес изображения на вход можно подавать как строкой (для одной картинки), так и массивом.
  • part
    Далее идет необязательный параметр, указывающий по сколько изображений загружать за раз. 0 — значит все разом, значение по умолчанию.
  • callback
    Ну и наконец коллбэк — функция, которая выполнится по завершении загрузки изображения. Ей можно указать свой параметр last , принимающий значение true , если эта часть последняя.

Второй вариант использования — загружать все изображения и фоновые картинки в элементе:

$("#elem").preload();

  • callback
    Функция, которая выполнится после загрузки всех изображений.

Примеры

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

Для корректной работы плагина требуется jQuery версии 1.6 или выше.

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

Но есть один нюанс, если событие hover возникает первый раз, то для загрузки изображения может потребоваться время. Пусть этот временной интервал будет и небольшим, но все же, иногда можно заметить короткую раздражающую задержку между наведением курсора над элементом и полным отображением изображения. Понятно, что в последующем, таких задержек не будет, так как браузеры добросовестно закешируют изображение. Но, как известно, первое впечатление от Вашего сайта должно быть только положительным, и не нужно его портить такими мелочами, тем более что их можно избежать. Как же решить такую, хоть и небольшую, но своеобразную проблему. Методов есть много, здесь наша веб студия познакомит Вас только с теми, которые решаются средствами css .

Первый прием заключается в том, что сразу же загружаем графическую составляющую, а потом убираем ее с видимой области при помощи свойства background-position, например установлением следующих смещений по x и y - -9999px -9999px. При наступлении события hover, применяем уже реальные значения, например, bottom left.

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

#random-unsuspecting-element { background: url(images/grass.png) no-repeat -9999px -9999px; }

#grass:hover { background: url(images/grass.png) no-repeat; }

Идея заключается в создании новых элементов, которые нужны только для предварительной загрузки изображений. Вы скажете, что это не самый лучший способ, ведь количество таких пустышек может быть огромным, решение же, далеко не будет элегантным. И Вы будете совершенно правы. Нам не нужны дополнительные элементы, так как мы можем со спокойной душой использовать и существующие. Все что нам необходимо, это использовать псевдоклассы:after или:before.

#something:before {

content: url("./img.jpg");

visibility:hidden;

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

Конечно же, можно применять для этих целей и javascript, но если Вам для создания сайта , достаточно будет приведенных выше решений, то почему бы ими и не воспользоваться.

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

С анимацией дела обстоят еще хуже. Представьте, например, что вам нужно реализовать на JS (JQuery) проезжаюшую легковую машину, заменяюшуюся через 2 секунды автобусом. Изображения с машиной и автобусом разные. При этом они начнут подгружаться только в тот момент, когда браузер получит на них ссылку с возможностью подгрузки (то есть в начале анимации ). На загрузку такой картинки нужно будет несколько секунд. То есть получается, что половину двухсекундной анимации это изображение только будет подгружаться - это не порядок.

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

Предзагрузка картинок на JavaScript (JQuery)

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

Сложно звучит? =) А выглядит всего лишь вот таким кодом, где нужно заменить путь к картинке на свой и все будет работать:

//создаем JQuery функцию, которая будет подгружать изображения в буфер jQuery.preloadImages = function() { for(var i = 0; i < arguments.length; i++) { jQuery("").attr("src", arguments[ i ]); } }; //указываем путь к изображению, которое нужно подгрузить $.preloadImages("/tpl/testimg.png");


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

$.preloadImages("imageone.jpg", "dirname/imageok.jpg", "/tpl/testimg.png");


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

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

Я лично во многих проектах предпочитаю использовать именно такой способ подгрузки ввиду того, что он удобен в реализации.

Предзагрузка изображений с помощью новых возможнестей HTML5

Этот способ появился относительно недавно ввиду того, что сама технология HTML5 была запущена не так давно. Суть его в том, что вы проставляете ссылку на картинку через тег link, а в атрибуте rel (тип подгружаемого элемента ) вы прописываете, что это предзагрузка. Тем самым браузер видит этот тег и автоматически загружает в буфер картинку .

Делается это добавлением в html код вот такого тега (только ссылку на изображение меняете на свою ):


Здесь в rel прописано 2 параметра: prerender - для его величества Chrome и prefetch - для остальных браузеров. Если вы хотите подгружать большее число картинок, то копируете тег и заменяете ссылку нужное количество раз:

Плюс этого способа в том, что отключение JS никак не повлияет на предзагрузку, но лично я вижу 2 явных недостатка:
1) Технология HTML5, а значит и этот способ предзагрузки, поддерживается далеко не всеми браузерами. Сейчас, правда, браузеры обновляются и большинство современных развивающихся браузеров распознают HTML5, но всеравно это еще далеко от идеала.
2) Более грамоздкий в отличае от JS реализации, ведь придется каждое изображение описывать отдельным тегом (причем с разными параметрами rel, что бы добиться чего-то близкого к кроссбраузерности ).

В общем считаю, что этот способ перспективен, но ему нужно время. Сейчас в нем не хватает универсальности .

Предварительная загрузка картинок на проверенном временем HTML

Самая первая идея, которая приходит обычно в голову на чистом html - это создать div блок с параметром CSS "display:none;" , в нем картинку и это должно стать предзагрузкой. На самом деле это не работает, браузер начнет загрузку в буфер только тогда, когда display станет отличное от none.

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

Размещение в невидимом блоке через CSS opacity и position (позиционирование)

В CSS есть такое свойство - opacity . Его предназначение - менять прозрачность и изменить прозрачность можно вплоть до нуля. Кроме того, в CSS есть еще и свойство position, которое нужно для позиционирования элемента на странице (можно попиксельно сдвигать блок с информацией хоть куда в пределах и за пределы видимости страницы ). Все это нам и пригодится:

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

Если вы хотите сделать прелоад нескольких картинок таким способом, то достаточно их указать внутри div блока, вот так:

Вот такие способы предзагрузки картинок/изображений можно использовать в разработке сайтов. Если у Вас есть еще какие-то идеи, то рад буду их почитать в комментариях.
Всем удачи в верстке и создании анимации! =)

Похожие статьи