Preloading the image. All comments to the note "Preloading images - an example of preloading images in HTML, JavaScript." Load by event

  • Translation
  • Tutorial

Fast and smooth loading of images is one of the important components of a good web interface. In addition, more and more sites are appearing that use large photographs in design; for such projects it is especially important to monitor the correct loading of graphics. This article describes several techniques that will help you control image loading.

Using a container for each image A simple method that can be applied to any image on the site. The trick is that each image is wrapped in a DIV, which prevents row-by-row loading:


Using the container, you can control the aspect ratio of the image and also use the loading indicator, which is very convenient if the images are heavy.

For example, to set the aspect ratio to 4:3, you could use the following CSS:

Img_wrapper( position: relative; padding-top: 75%; overflow: hidden; ) .img_wrapper img( position: absolute; top: 0; width: 100%; opacity: 0; )
To ensure that the image is displayed in the browser only after it has been fully loaded, you need to add an onload event for the image and use JavaScript to handle the event:


function imgLoaded(img)( var $img = $(img); $img.parent().addClass("loaded"); );
Function code inside HEAD tag should be located at the very end, after any jQuery or other plugin. After the image is fully loaded, it must be shown on the page:

Img_wrapper.loaded img( opacity: 1; )
For the effect of a smooth appearance of an image, you can use 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; )
A live example of this method is available.

Using a container for many images The previous method works well for individual images, but what if there are a lot of them on the page, for example a photo gallery or a slider? It is not advisable to upload everything at once - the pictures can weigh a lot. To solve this problem, you can force JavaScript to load only what you need into this moment image time. Example HTML markup for a slideshow:


We use the slideLoaded() function to control the process:

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 images are assigned the loaded class, and the overall progress is displayed. Again, JavaScript should be placed at the end of the HEAD tag, after everything else.

Caching On graphically heavy sites you can background, unnoticed by the user, load images into the browser cache. For example, there is a multi-page website, on one of internal pages which has a lot of graphic content. In this case, it would be advisable to load images into the cache even before the user switches to desired page. addresses of images in the array:

var heroArray = [ "/uploads/hero_about.jpg", "/uploads/hero_history.jpg", "/uploads/hero_contact.jpg", "/uploads/hero_services.jpg" ]
When a visitor enters the site, after loading home page, images begin to be loaded into the cache. To ensure that caching does not interfere with the display of current content, you need to add JavaScript functionality to the window load event:

Function preCacheHeros())( $.each(heroArray, function())( var img = new Image(); img.src = this; )); ); $(window).load(function())( preCacheHeros(); ));
This method improves the usability of the site, but puts additional load on the server. This must be kept in mind when implementing such functionality. In addition, it is necessary to take into account possible ways visitors to the site and cache images located on pages that the user is most likely to visit. To understand such paths through the site, it is necessary to analyze traffic statistics.

The event-based loading method is that images begin to be loaded after a certain event. This increases productivity and saves user traffic. HTML markup:


It's worth noting that the image URL is specified in data-src, not src. This is necessary so that the browser does not download the image immediately. Instead, src is loaded with a base64 transparent GIF pixel, which reduces the number of round trips to the server.

All that remains is to change the src value to data-src when the desired event occurs. JavaScript allows you to load images incrementally:

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(); );

Conclusion There is not one the best way in order to manage the loading of images on the site. In each specific case, it is necessary to choose the appropriate method, and also combine several, if appropriate. One of the main points that you need to pay attention to is performance and traffic. Simply put, first of all you should think about how it will be more convenient for the user site.
Why do we need to preload images? Most often we use it for high-quality drawing of interfaces and site controls. Example: There is a gallery script or text blocks with the ability to move (here/here). Graphic arrows are responsible for controlling movement. When you hover over an arrow, its image is replaced with another one.
What does the browser do on hover? It sends an image request to the server. Even with a very quick response, the “blinking” effect will be noticed. If you preload images, this will not happen. ApplicationB modern layout this approach is rarely used. It is much preferable to use CSS Sprites. But, if this is not possible and you really need it, welcome to the cat.

Var imgPath = "/tpl/images/"; // path to the directory with images // list of images var preloadImagesList = Array("about_hover.jpg", "news_hover.jpg", "photo_hover.jpg", "video_hover.jpg", "contacts_hover.jpg"); // / *******************************/ // function preload function preloadImages(images)( for(var i = 0; i< images.length; i++){ var image = images[i]; $("").attr("src", imgPath + image); )//for )//preloadImages /************************************* ****/ //function call $().ready(function())( preloadImages(preloadImagesList); ))

To play the game you need to load about 12 images in advance, and these images can vary from case to case. That is, now I need to load some 12 images (SVG), and tomorrow I will need another 12. Therefore, the option of placing them in is not suitable, because in this case you will have to constantly load all the images, and I only need 12 of them. Therefore, it was decided to load them using JavaScript before the start of the game. To do this, I implemented a small class "AssetsPreloader", which, so far, has the only method"preload", which takes an array of objects of the form (src: "link", id: "id") and loads required images by easy creation an instance of the Image() class (native).

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);

All loaded images end up in the static assets property of this class.

Next in the code is rendering the first frame of the game, where these images are already used. And, in general, the problem is that rendering does not occur. Code execution reaches it, I checked this, and after it the code is executed, but the images themselves are not drawn. As far as I understand, this happens because the images do not have time to load (even though they are loaded from disk). However, if you request to draw the first frame directly from the browser console, then everything works as it should and the frame is drawn normally.

The whole code generally looks something like this:

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();

In the end, the question comes down to how to load images (and various kinds of files in general) as correctly as possible so that until they are loaded, the code is not executed further. Moreover, perhaps there will be some kind of progress bar on the screen at this moment (that is, the script should not freeze completely either). The first thing that came to my mind was to add all the rest of the code in the callback to the preload() method, but this idea was not successful.

Please help. Interested not only in how, but also in what is the most correct way (best-practice, all that).

P.S. The script file is connected to the page with the defer attribute. When using, for example, async , rendering either happens or doesn’t (I can’t say what it depends on). But I don’t want to add handlers for checking page loading, DOM readiness, or something like that into the code itself.

To play the game you need to load about 12 images in advance, and these images can vary from case to case. That is, now I need to load some 12 images (SVG), and tomorrow I will need another 12. Therefore, the option of placing them in is not suitable, because in this case you will have to constantly load all the images, and I only need 12 of them. Therefore, it was decided to load them using JavaScript before starting the game. To do this, I implemented a small class "AssetsPreloader", which, for now, has a single "preload" method, which takes an array of objects of the form (src: "link", id: "id") and loads the necessary images by simply creating an instance of the class Image() (native).

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);

All loaded images end up in the static assets property of this class.

Next in the code is rendering the first frame of the game, where these images are already used. And, in general, the problem is that rendering does not occur. Code execution reaches it, I checked this, and after it the code is executed, but the images themselves are not drawn. As far as I understand, this happens because the images do not have time to load (even though they are loaded from disk). However, if you request to draw the first frame directly from the browser console, then everything works as it should and the frame is drawn normally.

The whole code generally looks something like this:

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();

In the end, the question comes down to how to load images (and various kinds of files in general) as correctly as possible so that until they are loaded, the code is not executed further. Moreover, perhaps there will be some kind of progress bar on the screen at this moment (that is, the script should not freeze completely either). The first thing that came to my mind was to add all the rest of the code in the callback to the preload() method, but this idea was not successful.

Please help. Interested not only in how, but also in what is the most correct way (best-practice, all that).

P.S. The script file is connected to the page with the defer attribute. When using, for example, async , rendering either happens or doesn’t (I can’t say what it depends on). But I don’t want to add handlers for checking page loading, DOM readiness, or something like that into the code itself.

Why do you need images at all? Let's imagine that you have an element on a website page, and you want its background image to show or change when you hover over it with the mouse. In principle, problems should not arise; everything can be solved simply: when creating a site in the style markup for the pseudo-class:hover of the desired element, we specify the path to the required image in the background property.

But there is one caveat: if the hover event occurs for the first time, then it may take time to load the image. Although this time interval may be small, sometimes you may notice a short, annoying delay between hovering over an element and the image being fully displayed. It is clear that in the future there will be no such delays, since browsers will cache the image in good faith. But, as you know, the first impression of your website should only be positive, and there is no need to spoil it with such trifles, especially since they can be avoided. How to solve such a small but unique problem? There are many methods, here our web studio will introduce you only to those that can be solved using css.

The first technique is to immediately load the graphic component, and then remove it from the visible area using the background-position property, for example by setting the following x and y offsets - -9999px -9999px. When the hover event occurs, we already apply real values, for example, bottom left.

What to do if the element already has background image, and when you hover the mouse cursor it must be changed. The above technique is no longer suitable as a solution. Usually in such cases sprites are used (combined background pictures) when the background position is shifted. If this method is not available to you, try the following. Apply an image to another element that exists on the page but that does not have a background image.

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

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

The idea is to create new elements that are only needed to preload images. You will say that this is not the best The best way, because the number of such dummies can be huge, but the solution will not be elegant. And you will be absolutely right. We don't need additional elements, since we can use existing ones with peace of mind. All we need is to use the:after or:before pseudo-classes.

#something:before (

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

visibility:hidden;

This option gives us the opportunity to preload images without creating additional elements.

Of course, you can use javascript for these purposes, but if the above solutions are enough for you to create a website, then why not use them.