Avoid an excessive DOM size when lazy loading images - javascript

I have a problem with dom size (3,044 elements).
I have a slider (Slick Slider) and images used in it causing DOM size prolem.
Img tag has lazy loading, it loads background image first and then loading main image data-src.
Reference to DOM size is this image :
<img src="/assets/img/img_bg_md.png" data-src="/uploads/images/202212/image_430x256_639c5b0a29f1f.webp" alt="Title" class="lazyload img-responsive img-post" width="1" height="1">
Is there a way to solve that problem ?

I'm not sure I understand what you want, but I'll try to help. You could set the already fixed image size to the image size you already know it will be. So you could put a background image of the image for it to load prettier
<style>
.img-responsive {
background-color: #ccc;
}
</style>
<img
src="/assets/img/img_bg_md.png"
data-src="/uploads/images/202212/image_430x256_639c5b0a29f1f.webp"
alt="Title"
class="lazyload img-responsive img-post"
style="width: 1px;height: 1px"
/ >
<script>
const imagens = document.querySelectorAll('.img-responsive');
var src, resp;
for (const imagem of imagens) {
src = imagem.getAttribute("data-src");
resp = src.match(/image_(\d+)x(\d+)_/);
if(const && resp.length > 2){
imagem.style.width = resp[1] + 'px';
imagem.style.height = resp[2] + 'px';
}
imagem.onload = function() {
imagem.parentElement.style.backgroundColor = 'transparent';
imagem.style.width = imagem.naturalWidth + 'px';
imagem.style.height = imagem.naturalHeight + 'px';
}
}
</script>
Other suggestions:
There are a few things you can try to reduce the DOM size when using lazy loading for images:
Use a lighter version of the main image as the background image. This can help reduce the size of the DOM element and also improve the loading speed of the page.
Use a placeholder image as the background image. This can help reduce the size of the DOM element and also improve the loading speed of the page.
Use a smaller image as the background image. This can help reduce the size of the DOM element and also improve the loading speed of the page.
Use responsive images. By using the srcset attribute, you can specify different sizes of the same image for different screen sizes, which can help reduce the size of the DOM element and also improve the loading speed of the page.
Use image optimization tools. There are several tools available that can help you optimize your images, which can reduce the size of the DOM element and improve the loading speed of the page.
Use a content delivery network (CDN). By using a CDN, you can offload the delivery of your images to a network of servers around the world, which can help reduce the size of the DOM element and improve the loading speed of the page.
It's worth noting that there is no one-size-fits-all solution to this problem, and you may need to try a combination of these approaches to find the best solution for your specific use case.

Related

How to preload images with multiple srcset with javascript or jQuery?

I'm trying to build a script to preload images with jQuery, for a small application I'm working on.
I've read different tutorials and right now I managed to have it working like this:
var imageList = ['img1.png', 'img2.png', 'img3.png'];
$.each(imageList, function (index, imageName) {
var $img = $('<img>')[0];
$img.onload = function () {
console.log('loaded');
};
$img.src = imgPath + imageName;
}
This works fine. I load the images from an array I prepare, I then create all the img tags and then append them in the DOM where needed.
I'm wondering now, though, how can I do something similar if I have images with multiple srcset.
Let's say I have 3 sizes for each image, but they could be more, normally I would put something like this in the html:
<img srcset="large.jpg 1024w,
medium.jpg 640w,
small.jpg 320w"
sizes="(min-width: 36em) 33.3vw, 100vw"
src="small.jpg">
Now, how shall I apply the preloading to this?
1) I could preload all the sizes for each image in Javascript, but this would be pointless, because the whole purpose of having multiple srcset is to load just one
2) I could put the img tag in the DOM, let the browser choose the only size needed and load from Javascript.
The problem with the second option is that the browser is loading the images from the DOM, so why loading them again in Javascript? It's possible that I am completely wrong about this and maybe I'm missing something. What's the correct way to do it?
You can use the same idea that you had in your script, but instead set the sizes and srcset attributes.
const image = new Image()
image.onload = () => console.log('loaded')
image.sizes = '(min-width: 36em) 33.3vw, 100vw'
// This will trigger the browser to start loading the appropriate picture
image.srcset = `
large.jpg 1024w,
medium.jpg 640w,
small.jpg 320w
`
Can't you detect the browser width in Javascript, and use that to load the proper images? You could have one array for small images, one for medium, and one for large.
Even better, if you'd name the images such that the size is a suffix (image1_small.png and image1_large.png) you'd only need one array, and just append the correct suffix.
Alternatively, keep separate directories, small/ large/ etc and just give the proper path, according to window width.

How to fix image wrap size with the same size of Lazy Load image?

I'm looking for to show background-color image before lazy-loading with exactly the same dimension of the image. My script gest width and height of each images and applises on image-wrap.
Here is my code:
$(document).ready(function() {
$('section .lazywrap').each(function() {
var lazyWrap = $(this);
var img = $(lazyWrap, this);
lazyWrap.width(img.width());
lazyWrap.height(img.height());
console.log(lazyWrap.height());
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<a href="/" class="lazy-wrap">
<img class="lazy" width="472" src="img.jpg" data-original="img.jpg">
</a>
Web browser can get height value even if it's not implemented in <img>, BUT only for images who are visible in the viewport when the page is loading, because of lazy Load.
I read lot of things about responsive background image with the padding-bottom trick, but in my case I really need the real width and height value on this "background preview" and not a ratio. All my image have different height value.
Finally, I found an alternative solution with de lazy load plugin call lazysizes. It allows to use an background color with exactly the size instead of the image is being loading.

Proper method for simple 'lazy loading' of images

I am building a web application that is extremely image heavy. A feature of it is an interactive timeline which allows the user to scroll through a series of years. Each year has a photo gallery with 20-50 images. I am looking for the best solution to hide images on load, and load them on demand (a click event). Here are a few options:
1) Use javascript to assign the data-src to the actual src on demand.
<img src="blank.png" data-src="images/real-image.jpg">
2) Place all images inside a div with display:none. I believe some browsers still load these images on load, so might not be a good idea
<div style="display:none">
<img src="images/real-image.jpg">
</div>
3) Use a technique like lazyload. This plug, JAIL allows for images to be loaded after an event is triggered.
Thanks in advance!
Number one is good. Just but let src point to nowhere src=""or to a single placeholder image. If you need the image file, switch src with the real path, and the Browser loads it. Switch again for removal, then the file is fair game for the gargabe collector.
Number two will just hide but still load the image.
Number three basically does what Number one does.
(First post, no reputation, still hope I can help).
I use the following technique:
// Contains Image path strings that can be loaded statically or dynamically
var imgs = [img1, img2, img3, img4];
var img = new Image();
img.style.cssText = "position: absolute; visibility: hidden; display: block";
document.body.appendChild(img);
for (var i = 0 ; i < imgs.length ; i++)
img.src = imgs[i];
Each iteration posts an HTTP request for the image, which is later cached upon arrival.
This works for me. I load the string paths into the HTML using a server-side generation.

Prevent large image flickering on src change

I've a problem with image flickering with large images.
In my body i have 5 images:
<img id="img1" src="img1.png" width="250">
<img id="img2" src="img2.png" width="250">
<img id="img3" src="img3.png" width="250">
<img id="img4" src="img4.png" width="250">
<img id="img5" src="img5.png" width="250">
and one I'm dragging one of them with jQuery UI, all are changing their src and on dragend as well:
function dragStart() {
$('#img2').attr('src','newimg2.png');
$('#img3').attr('src','newimg3.png');
$('#img4').attr('src','newimg4.png');
$('#img5').attr('src','newimg5.png'); }
so fine so good. But I need to use large images (2000 x 2000px) because all images can be clicked and then they will animate to the full size of the viewport that they dont pixelate.
$this.animate(
{ width: 1800, top: -650, left: -250 },
{
duration: 4000,
easing: 'easeOutElastic'
})
I think because of the size of every image, they are flickering. Does anyone of you have an idea how to prevent this flickering on images, if all src change at the same time ?
Thanks for your effort
The problem you described does not sound like a pre-loading issue to me.
For preloading would happen, when you load ANOTHER image from the server once you start to move it around. But like I have read your Question you are moving the DOM-object containing your image in SRC around.
Thats most likely a Browser issue, because he has to scale your images down from 2k x 2k to lets say 100 x 100. That is some expensive interpolation stuff to do there.
So your main problem could be, like you mentioned, the size of the image.
Even preloading would not be of use, because you would have the same issues then.
In my eyes you should have two versions of your image: One small one (the size you want to drag around) and a big one, the one you want to display.
The big one can either be loaded automatically in background or on demand, when a user clicks on an image.
In the web it is quite common, to show scale the small image to screen size with smooth animations and start to preload in the background and when the preload finished, replace the fullscreen image to remove the pixel effect.
I hope I made myself clear.
The key to what you are trying to do is called preloading. However, you'll need to think carefully about how you want to do this.
Preloading involves loading the image in an img tag off-screen, but still in the DOM. This caches the image locally, which means that the next time you attempt to use the same source, it'll pull from cache instead of querying the server for the image (and, thus, flicker).
Preloading an image is a simple matter:
(new Image()).src="mysource.png";
What you want to decide is when you want to load the images. IF you load them all at first, you'll potentially use up a lot of bandwidth. If you load them on-click, you'll get buffering.
You can check if an image is loaded using the onload event present on img tags and wrapped within jQuery if needed, as follows:
var i = new Image();
i.onload = function() {
console.log("Loaded");
}
i.src = "mysource.png";
Credits to Robin Leboeuf for the concise Image() form.
You can use a function like this to preload your images:
function imagesPreload(){
var imgArray = new Array("path/to/img1.jpg", "path/to/img2.jpg", "path/to/img3.jpg");
for (var i=0; i<imgArray.length; i++) {
(new Image()).src = imgArray[i];
}
}
See the comments. You should ensure that the images are loaded before you show them. This is called pre-loading and can e.g. be achieved by having hidden images (not using display:none but placing them offscreen) that have the SRC that you want.
Edit: see the more elaborate answer by #Sebástien !

Programmatically Clip/Cut image using Javascript

Are there any documents/tutorials on how to clip or cut a large image so that the user only sees a small portion of this image? Let's say the source image is 10 frames of animation, stacked end-on-end so that it's really wide. What could I do with Javascript to only display 1 arbitrary frame of animation at a time?
I've looked into this "CSS Spriting" technique but I don't think I can use that here. The source image is produced dynamically from the server; I won't know the total length, or the size of each frame, until it comes back from the server. I'm hoping that I can do something like:
var image = getElementByID('some-id');
image.src = pathToReallyLongImage;
// Any way to do this?!
image.width = cellWidth;
image.offset = cellWidth * imageNumber;
This can be done by enclosing your image in a "viewport" div. Set a width and height on the div (according to your needs), then set position: relative and overflow: hidden on it. Absolutely position your image inside of it and change the position to change which portions are displayed.
To display a 30x40 section of an image starting at (10,20):
<style type="text/css">
div.viewport {
overflow: hidden;
position: relative;
}
img.clipped {
display: block;
position: absolute;
}
</style>
<script type="text/javascript">
function setViewport(img, x, y, width, height) {
img.style.left = "-" + x + "px";
img.style.top = "-" + y + "px";
if (width !== undefined) {
img.parentNode.style.width = width + "px";
img.parentNode.style.height = height + "px";
}
}
setViewport(document.getElementsByTagName("img")[0], 10, 20, 30, 40);
</script>
<div class="viewport">
<img class="clipped" src="/images/clipped.png" alt="Clipped image"/>
</div>
The common CSS properties are associated with classes so that you can have multiple viewports / clipped images on your page. The setViewport(…) function can be called at any time to change what part of the image is displayed.
In answer to :
Alas, JavaScript simply isn't capable of extracting the properties of the image you'd require to do something like this. However, there may be salvation in the form of the HTML element combined with a bit of server-side scripting.
...
< ? (open php)
$large_image = 'path/to/large_image';
$full_w = imagesx($large_image);
$full_h = imagesy($large_image);
(close php) ? >
This can be done in Javascript, just google a bit :
var newimage = new Image();
newimage.src = document.getElementById('background').src;
var height = newimage.height;
var width = newimage.width;
This generates a new image from an existing one and captures this way in java script the original height and width properties of the original image (not the one id'ed as background.
In answer to :
The width/height properties of the document's image object are read only. If you could change them, however, you would only squish the frames, not cut the frames up like you desire. The kind of image manipulation you want can not be done with client-side javascript. I suggest cutting the images up on the server, or overlay a div on the image to hide the parts you do not wish to display.
...
var newimage = new Image();
newimage.src = document.getElementById('background').src;
var height = newimage.height;
var width = newimage.width;
newimage.style.height = '200px';
newimage.style.width = '200px';
newimage.height = '200px';
newimage.width = '200px';
and if wanted :
newimage.setAttribute('height','200px');
The doubled newimage.style.height and newimage.height is needed in certain circumstances in order to make sure that a IE will understand in time that the image is resized (you are going to render the thing immediately after, and the internal IE processing is too slow for that.)
Thanks for the above script I altered and implemented on http://morethanvoice.net/m1/reader13.php (right click menu... mouseover zoom lent) correct even in IE , but as you will notice the on mousemove image processing is too fast for the old styled IE, renders the position but only once the image. In any case any good idea is welcome.
Thanks to all for your attention, hope that the above codes can help someone...
Claudio Klemp
http://morethanvoice.net/m1/reader13.php
CSS also defines a style for clipping. See the clip property in the CSS specs.
The width/height properties of the document's image object are read only. If you could change them, however, you would only squish the frames, not cut the frames up like you desire. The kind of image manipulation you want can not be done with client-side javascript. I suggest cutting the images up on the server, or overlay a div on the image to hide the parts you do not wish to display.
What spriting does is essentially position a absolutely-positioned DIV inside another DIV that has overflow:hidden. You can do the same, all you need to do is resize the outer DIV depending on the size of each frame of the larger image. You can do that in code easily.
You can just set the inner DIV's style:
left: (your x-position = 0 or a negative integer * frame width)px
Most JavaScript Frameworks make this quite easy.
Alas, JavaScript simply isn't capable of extracting the properties of the image you'd require to do something like this. However, there may be salvation in the form of the HTML <canvas> element combined with a bit of server-side scripting.
PHP code to go about extracting the width and height of the really large image:
<?php
$large_image = 'path/to/large_image';
$full_w = imagesx($large_image);
$full_h = imagesy($large_image);
?>
From here, you'd then load the image into a <canvas> element, an example of which is documented here. Now, my theory was that you may be able to extract pixel data from a <canvas> element; assuming that you can, you would simply make sure to have some form of definite divider between the frames of the large image and then search for it within the canvas. Let's say you found the divider 110 pixels from the left of the image; you would then know that each "frame" was 110 pixels wide, and you've already got the full width stored in a PHP variable, so deciphering how much image you're working with would be a breeze.
The only speculative aspect to this method is whether or not JavaScript is capable of extracting color data from a specified location within an image loaded into a <canvas> element; if this is possible, then what you're trying to accomplish is entirely feasible.
I suppose you want to take a thumbnail for your image. You can use ImageThumbnail.js that created from prototype library in this way:
<script type="text/javascript" src="prototype.js"></script>
<script type="text/javascript" src="ImageThumbnail.js"></script>
<input type="file" id="photo">
<img src="empty.gif" id="thumbnail" width="80" height="0">
<script type="text/javascript">
<!--
new Image.Thumbnail('thumbnail', 'photo');
//-->
</script>
for more information
try use haxcv library haxcv js by simple functions
go to https://docs.haxcv.org/Methods/cutImage to read more about his library
var Pixels = _("img").cutImage (x , y , width , height );
_("img").src (Pixels.src);
// return cut image
but try to include library first

Categories

Resources