Предзагрузка изображения. Все комментарии к заметке "Предзагрузка картинок - пример предварительной загрузки изображений на HTML, JavaScript". Загрузка по событию

  • Перевод
  • Tutorial

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

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


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

Например, чтобы задать соотношение сторон 4:3, можно использовать следующий CSS:

Img_wrapper{ position: relative; padding-top: 75%; overflow: hidden; } .img_wrapper img{ position: absolute; top: 0; width: 100%; opacity: 0; }
Для того, чтобы изображение отображалось в браузере только после полной подгрузки, необходимо добавить событие onload для изображения и использовать JavaScript, который будет обрабатывать событие:


function imgLoaded(img){ var $img = $(img); $img.parent().addClass("loaded"); };
Код функции внутри тега HEAD должен быть расположен в самом конце, после любого jQuery или другого плагина. После полной подгрузки изображения его необходимо показать на странице:

Img_wrapper.loaded img{ opacity: 1; }
Для эффекта плавного появления картинки можно использовать CSS3 transition:

Img_wrapper img{ position: absolute; top: 0; width: 100%; opacity: 0; -webkit-transition: opacity 150ms; -moz-transition: opacity 150ms; -ms-transition: opacity 150ms; transition: opacity 150ms; }
Живой пример этого способа можно .

Использование контейнера для множества изображений Предыдущий способ хорошо подходит для отдельных изображений, а что если на странице их много, например галерея фотографий или слайдер? Подгружать сразу все нецелесообразно - картинки могут много весить. Для решения этой проблемы можно заставить JavaScript"ом загружать только нужные в данный момент времени изображения. Пример HTML-разметки для слайдшоу:


Используем функцию slideLoaded(), чтобы контролировать процесс:

Function slideLoaded(img){ var $img = $(img), $slideWrapper = $img.parent(), total = $slideWrapper.find("img").length, percentLoaded = null; $img.addClass("loaded"); var loaded = $slideWrapper.find(".loaded").length; if(loaded == total){ percentLoaded = 100; // INSTANTIATE PLUGIN $slideWrapper.easyFader(); } else { // TRACK PROGRESS percentLoaded = loaded/total * 100; }; };
Подгруженным изображениям присваивается класс loaded, а также отображается общий прогресс. И снова, JavaScript должен быть помещен в конец тега HEAD, после всего остального.

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

var heroArray = [ "/uploads/hero_about.jpg", "/uploads/hero_history.jpg", "/uploads/hero_contact.jpg", "/uploads/hero_services.jpg" ]
Когда посетитель заходит на сайт, после загрузки главной страницы, начинают загружаться изображения в кэш. Для того, чтобы кэширование не мешало отображению текущего контента, необходимо функционал JavaScript добавить в событие window load:

Function preCacheHeros(){ $.each(heroArray, function(){ var img = new Image(); img.src = this; }); }; $(window).load(function(){ preCacheHeros(); });
Такой способ улучшает удобство использования сайта, однако дает дополнительную нагрузку на сервер. Это нужно иметь в виду при внедрении подобного функционала. Кроме того, необходимо обязательно учитывать возможные пути посетителей на сайте и кэшировать изображения, расположенные на страницах, которые пользователь вероятнее всего посетит. Чтобы понять такие пути по сайту, необходимо анализировать статистику посещаемости.

Загрузка по событию способ заключается в том, что изображения начинают подгружаться после определенного события. Это увеличивает производительность и экономит трафик пользователя. HTML-разметка:


Стоит заметить, что URL изображение задано в data-src, а не в src. Это необходимо, чтобы браузер не загружал картинку сразу. Вместо этого в src загружается прозрачный пиксель в GIF, заданный в base64, что уменьшает количество обращений к серверу.

Остается только при нужном событии изменить значение src на data-src. JavaScript позволяет загружать изображения постепенно:

Function lazyLoad(){ var $images = $(".lazy_load"); $images.each(function(){ var $img = $(this), src = $img.attr("data-src"); $img .on("load",imgLoaded($img)) .attr("src",src); }); }; $(window).load(function(){ lazyLoad(); };

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

Для игры нужно подгрузить заранее в районе 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 или что-то в этом роде не хочу.

Зачем вообще нужна изображений? Представим себе, что у Вас есть элемент на странице сайта, и Вы хотите, чтобы при наведении на него мышкой показывалась или изменялась его фоновая картинка. Проблем, в принципе, не должно возникнуть, все решается просто: при создании сайта в стилевой разметке для псевдокласса: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, но если Вам для создания сайта , достаточно будет приведенных выше решений, то почему бы ими и не воспользоваться.