Load a low-res background image first, then a high-res one - html

I am trying to optimize the size of my site when it is being outputted to the client. I am down to 1.9MB and 29KB when caching. The issue is that the first load contains an image which is very unoptimized for mobile devices; it has a 1080p resolution.
So I am looking for a method that allows me to first load a low-res version (min.bg.jpg) and once the site has loaded, use a high-res version - or even one with a resolution close to the device being used (NNNxNNN.bg.jpg or just bg.jpg).
The background is set using CSS just like everyone would expect. Its applied to the body and the entire statement looks like this:
body {
background: url("/cdn/theme/images/bg.jpg");
color: white;
height: 100%;
width: 100%;
background-repeat: no-repeat;
background-position: 50% 50%;
background-attachment: fixed;
}
Now, I want to change that to use min.bg.jpg instead for the first load, and then something like this:
jQuery(function(){
jQuery("body").[...]
});
Which way do I go on asynchronously downloading the new background, and then inserting it as the new CSS background image?
To show some differences, here is an example of the main and mini version I am using for testing:
Ingwie#Ingwies-Macbook-Pro.local ~/Work/BIRD3/cdn/theme/images $ file *.jpg
bg.jpg: JPEG image data, EXIF standard
min.bg.jpg: JPEG image data, JFIF standard 1.01
Ingwie#Ingwies-Macbook-Pro.local ~/Work/BIRD3/cdn/theme/images $ du -h *.jpg
1,0M bg.jpg
620K min.bg.jpg

A bit late, but you can use this extremely simple solution:
You can put the two images in the css background:
background-image: url("high-res.jpg"),url("low-res.jpg");
The browser will display the low-res image fist, then display the high-res over the low-res when it has been loaded.

Let's try a basic one :
<img border="0"
style="background:url(http://i.stack.imgur.com/zWfJ5.jpg) no-repeat;
width:1920px;
height:1200px"
src="http://i.stack.imgur.com/XOYra.jpg" width="1920" height="1200" />
zWfJ5.jpg is the low-resolution version, and XOYra.jpg is the high-resolution version.
If there is a way to arrange the loading so the background-image displays first, this could be the simplest i can think of.
where low resolution 44k:
and high resolution is 1.16M
result :
jsFiddled here ( this needs a bigger image for loading comparison. )

Here's the method I use...
CSS:
#div_whatever {
position: whatever;
background-repeat: no-repeat;
background-position: whatever whatever;
background-image: url(dir/image.jpg);
/* image.jpg is a low-resolution at 30% quality. */
}
#img_highQuality {
display: none;
}
HTML:
<img id="img_highQuality" src="dir/image.png">
<!-- img.png is a full-resolution image. -->
<div id="div_whatever"></div>
JQUERY:
$("#img_highQuality").off().on("load", function() {
$("#div_whatever").css({
"background-image" : "url(dir/image.png)"
});
});
// Side note: I usually define CSS arrays because
// I inevitably want to go back and add another
// property at some point.
What happens:
A low-res version of the background quickly loads.
Meanwhile, the higher resolution version is loading as a hidden image.
When the high-res image is loaded, jQuery swaps the div's low-res image with the high-res version.
PURE JS VERSION
This example would be efficient for changing one to many elements.
CSS:
.hidden {
display: none;
}
#div_whatever {
position: whatever;
background-repeat: no-repeat;
background-position: whatever whatever;
background-image: url(dir/image.jpg);
/* image.jpg is a low-resolution at 30% quality. */
}
HTML:
<div id="div_whatever"></div>
<img id="img_whatever" class="hidden" src="dir/image.png" onload="upgradeImage(this);">
JAVASCRIPT:
function upgradeImage(object) {
var id = object.id;
var target = "div_" + id.substring(4);
document.getElementById(target).style.backgroundImage = "url(" + object.src + ")";
}
UPDATE / ENHANCEMENT (1/31/2017)
This enhancement is inspired by gdbj's excellent point that my solution results in the image path being specified in three locations. Although I didn't use gdbj's addClass() technique, the following jQuery code is modified to extract the image path (rather than it being hardwired into the jQuery code). More importantly, this version allows for multiple low-res to high-res image substitutions.
CSS
.img_highres {
display: none;
}
#div_whatever1 {
width: 100px;
height: 100px;
background-repeat: no-repeat;
background-position: center center;
background-image: url(PATH_TO_LOW_RES_PHOTO_1);
}
#div_whatever2 {
width: 200px;
height: 200px;
background-repeat: no-repeat;
background-position: center center;
background-image: url(PATH_TO_LOW_RES_PHOTO_2);
}
HTML
<div id="div_whatever1"></div>
<img id="img_whatever1" class="img_highres" src="PATH_TO_HIGH_RES_PHOTO_1">
<div id="div_whatever2"></div>
<img id="img_whatever2" class="img_highres" src="PATH_TO_HIGH_RES_PHOTO_2">
JQUERY
$(function() {
$(".img_highres").off().on("load", function() {
var id = $(this).attr("id");
var highres = $(this).attr("src").toString();
var target = "#div_" + id.substring(4);
$(target).css("background-image", "url(" + highres + ")");
});
});
What's happens:
Low res images are loaded for each of the divs based on their CSS
background-image settings. (Note that the CSS also sets the div to the intended
dimensions.)
Meanwhile, the higher resolution photos are being
loaded as hidden images (all sharing a class name of img_highres).
A jQuery function is triggered each time an img_highres photo
completes loading.
The jQuery function reads the image src path, and
changes the background image of the corresponding div. In the
example above, the naming convention is "div_[name]" for the visible divs
and "img_[same name]" for the high res images loaded in the
background.

I would normally optimise the image using Grunt or an online tool such as Tiny PNG to reduce the file size.
Then you could choose to defer the loading of the images, I found the following article helpful when it came to deferring images - https://www.feedthebot.com/pagespeed/defer-images.html
The article discusses using a base64 image for the initial loading and then deferring the loading of the high-quality image. The image mark up mentioned in the article is as follows...
<img src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-src="your-image-here">
The JavaScript mentioned in the article is as follows...
window.addEventListener("load", () => {
const images = document.querySelectorAll("img");
for (let img of images)
if (img.hasAttribute("data-src"))
img.src = imgDefer[i].getAttribute("data-src");
});
I hope this helps.

On Ubuntu / Chrome 71, Milche's answer does not work consistently for me and the higher resolution image (via img src) often loads and resolves before the lower resolution image (via css background) even begins downloading.
My solution is to start with the lower res image as the src and use the Image class to create an unattached <img> instance with the high res image. Once it loads, then update the existing <img> source with the high res image source.
HTML:
<img id='my-image' src='low-res.png' alt='Title' width='1920px' height='1200px'>
JavaScript:
window.addEventListener('load', function() {
loadHighResImage(document.getElementById('my-image'), 'high-res.png')
})
function loadHighResImage(elem, highResUrl) {
let image = new Image()
image.addEventListener('load', () => elem.src = highResUrl)
image.src = highResUrl
}
Fiddle: https://jsfiddle.net/25aqmd67/
This approach works for lower res images that are simply scaled down as well.

All answers above mostly work with a little adjustment, but here is the way I think short and simple to kick off.
Note:
Uncomment the code load the high-resolution image for usage, a sleep function is just for simulating a slow network.
Actually, this method does not load 2 resources (low and high) simultaneous, but it's acceptable because low resource won't take much time to load.
Just copy whole code and run for a quick check.
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
<style type="text/css">
</style>
</head>
<body>
<!-- Load low res image first -->
<img style="width: 400px; height: auto;" alt="" src="https://s3-ap-southeast-1.amazonaws.com/wheredat/banner-low-quality/banner_20180725_123048.jpg" onload="upgrade(this)">
</body>
<script type="text/javascript">
function upgrade(image){
// After load low res image, remove onload listener.
// Remove onload listener.
$(image).prop("onload", null);
// Load high resolution image.
// $(image).attr('src', 'https://s3-ap-southeast-1.amazonaws.com/wheredat/banner/banner_20180725_123048.jpeg');
// Simulate slow network, after 1.5s, the high res image loads.
sleep(1500).then(() => {
// Do something after the sleep!
// Load a high resolution image.
$(image).attr('src', 'https://s3-ap-southeast-1.amazonaws.com/wheredat/banner/banner_20180725_123048.jpeg');
});
}
// Sleep time expects milliseconds
function sleep (time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
</script>
</html>

Related

Is it possible to maximize the dimension of a specific image according to the size of a browser window using greasemonkey/tampermonkey?

For instance if I have a gallery of images that I can browse through, sometimes having multiple galleries open, I have to be careful in resizing one window because it will resize differently for another one of the same page.
The best example I can think of is when you open an image by itself in a new tab and it's auto resized proportionally in the middle of the page no matter big or small the window is. No scrolling required
If it helps here's an example of the code code where the image is shown
<div id="i3">
<a onclick="return load_image(2, 'f46ef2b433')" href="https://testsite.com/b/f46ef2b433/1341428-2">
<img id="img" src="http://testsite.com/fold01/5dde3b620790893d3ffab2da2437077dd41b31cf-230842-1280-1820-jpg/keystamp=1550591100-88d6d61f5f;fileindex=66272627;xres=2400/_000.jpg"
style="height: 1820px; width: 1280px; max-width: 1280px; max-height: 1820px;" onerror="this.onerror=null; nl('27617-430719')"></a></div>
the xpath is: //*[#id="img"]
I've seen plugins do this with videos but I'm looking to just do it with an image. Looking at other "similar" examples is confusing me more than helping at this point
(function() {
'use strict';
var x;
x = document.getElementById("img");
x.style.maxHeight = "100vh";
x.style.maxWidth = "100vw";
x.style.width = "";
x.style.height = "";
x.style.position = "fixed";
x.style.top = "0";
x.style.left = "15%";
})();
Here is my current updated script. i've been unable to change the max-height and max-with values but everything else has worked out for the most part. Without that, I'm not able to finish the task unless there's another method
x.setAttribute("style", "max-Height: 100vh");
this works but wiped away all of the other attributes...
both seem to work only in the console and not in the script as far as modifying the max height and max width values. there's no problem with changing other values
From what you described, you can use vh and vw units. Those units are relative to the size of the viewport.
Try the following exemple in a empty page. The display: body on the image avoid to have a vertical scrollbar
html,
body {
margin: 0;
padding: 0;
}
img {
display: block;
max-height: 100vh;
max-width: 100vw;
}
<a href="https://stackoverflow.com">
<img src="http://www.dummyimage.com/1000x4000/000/fff&text=1000x4000">
</a>

Load image on hover over <a>

While I wasn't that concerned about it in the beginning, I noticed that my page size is about 9 MB (+/- 200 images). I want to somehow decrease this by only loading the image when the user hovers over the specific <a>, so that only that image is loaded (which should decrease the page size drastically).
The code below is what I'm using right now
<style>
div.img {
display: none;
position: absolute;
}
a:hover + div.img {
display: block;
}
</style>
<div>
Some Name
<div class="img">
<img src="http://sub.domain.com/somename.jpg" alt="Some Name" style="some styles">
</div>
</div>
I think it's possible with jQuery, but I don't know where to start.
Thanks in advance.
Well if you have around 200 images in your directory, when a client requests the webpage it is going to have to download the images to have them ready if you are using a single page layout. I would look into lazy loading just as Adam stated. If you can also I would suggest to try to compress the photos if you can to lower the file size if possible. Good luck!
I fixed my problem by adapting an existing pen-code to adjust my needs (using jQuery). It now works again in IE/Firefox
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(document).ready(function($) {
$('.trigger').mouseover(function() {
// find our span
var elem = $(this).siblings('span');
// get our img url
var src = elem.attr('data-original');
// change span to img using the value from data-original
elem.replaceWith('<img src="' + src + '" style="display:block;position:absolute;"/>');
});
$('.trigger').mouseout(function() {
// find our span
var elem = $(this).siblings('img');
// get our img url
var src = elem.attr('src');
// change span to img using the value from data-original
elem.replaceWith('<span data-original="'+src+'"></span>');
});
});
</script>
Hover over me to fetch an image
<span data-original="https://lorempixel.com/g/150/200/"></span>
you can put the image with no src attribute and put the specific src in the href of div or the image!
then use jquery to get the href of a or data-src of image and then give it to the image the code will be something like this:
<a class="image" href="the-src-of-the-image">
<img src="(leave this blank)">
</a>
and this is the jquery
jQuery(document).ready(function($){
$('.image').on('hover',function(){
var img_src = $(this).attr('href');
$(this).children('img').attr('src',img_src);
});
});

How to cache SVG icons on an external CDN while avoiding FOMI?

I know how to get SVG icons loading on my website, but what I can't figure out is how to satisfy all the following constraints:
Ability to use SVG icons in CSS
No flash of missing icons (FOMI)
Minimal initial page size
Cached SVGs
Ability to use a CDN
Must be able to use fill: currentColor to make the icon match the current text color, just like icon-fonts
Bonus: Pixel-align the SVGs so they always look sharp
1,2,3 and 4 can be satisfied by using an external sprite map like so:
<svg viewBox="0 0 100 100">
<use xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="/assets/sprite-4faa5ef477.svg#icon-asterisk-50af6"></use>
</svg>
But we can't use a CDN until browsers fix the CORS issue.
We can patch in support for external domains, but I'm pretty sure this won't work for CSS because it only watches the DOM (sorry, haven't tested yet), and also it causes your browser to make a whole bunch of failed requests to a file it can't fetch (one for each icon on the page).
We can use a CDN if instead we either inline the entire SVG (increased page size, no caching) or we AJAX it in (causes FOMI).
So, are there any solutions that satisfy all 5 7 constraints?
Basically I want SVGs to be just as convenient as icon-fonts or there's no point switching over. SVGs support multiple colors and are more accessible but I can't get them to look as good, or load as efficiently.
The closest I could get is loading an SVG in an image element and then using it like an "old-fashioned" image sprite. This, as far as I can tell, satisfies all of your constraints. The only disadvantage I can think of is that you lose the ability to modify specific parts of the SVG using CSS. This is however not one of your constraints (correct me if I'm wrong) and it is still possible to modify all of the icon, as you can see in my demo. I created a fiddle and for completeness also include a code snippet.
To emulate a CDN, I created an SVG file and uploaded it to some image hosting service. My apologies to future readers if this service is now down. The SVG file simply has all icons next to each other in it (I created a black square, circle and triangle for now). The difference with SVG sprite maps is thus that the icons are in the SVG itself, not in the defs. It should be quite easy to combine multiple SVGs in a single one, I have not looked for tools that would automate this process.
.icon {
display: inline-block;
vertical-align: top;
width: 30px; /* can be anything */
height: 30px;
background-image: url('http://imgh.us/icons_36.svg');
border: 1px solid #000; /* just to see where the icon is */
}
/* sizes */
.icon.large {
width: 50px;
height: 50px;
background-size: 150px auto;
}
/* icons */
.icon.circle { background-position: -30px 0; }
.icon.large.circle { background-position: -50px 0; }
.icon.triangle { background-position: -60px 0; }
.icon.large.triangle { background-position: -100px 0; }
/* styles */
.icon.info {
/* based on http://stackoverflow.com/a/25524145/962603,
* but you can of course also use an SVG filter (heh) */
filter: invert(100%) sepia(100%) saturate(50000%) hue-rotate(90deg) brightness(70%);
}
.icon.highlight {
/* based on http://stackoverflow.com/a/25524145/962603,
* but you can of course also use an SVG filter (heh) */
filter: invert(100%) sepia(100%) saturate(10000%) hue-rotate(30deg) brightness(50%);
}
<span class="icon square"></span>
<span class="icon circle"></span>
<span class="icon triangle"></span>
<span class="icon circle highlight"></span>
<span class="icon triangle large info"></span>
My best guess is to use data uris, which have pretty great browser support. Via something like Grunticon or their web app Grumpicon.
The output is 2 css files and 1 js that should work seamlessly with your CDN.
The rendered output is very flexible and customizable.
I had pretty much the same problem. This probably doesn't satisfy the FOMI requirement, but it's an interesting hack that got me out of a bind. Basically, this script just swaps every img in the DOM that imports an svg with inline SVG, so you can style it how you want.
// replaces img tags with svg tags if their source is an svg
// allows SVGs to be manipulated in the DOM directly
// 💡 returns a Promise, so you can execute tasks AFTER fetching SVGs
let fetchSVGs = () => {
//gets all the SRCs of the SVGs
let parentImgs = Array.from(document.querySelectorAll('img')).map((img) => {
if(img.src.endsWith('.svg')) {
return img
}
});
let promises = [];
parentImgs.forEach((img) => {
promises.push(
fetch(img.src).then((response) => {
// Error handling
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' +
response.status);
return;
}
// saves the SVG
return response.text();
})
)
});
// All fetch() calls have been made
return Promise
.all(promises)
.then((texts)=> {
texts.forEach((text, i) => {
let img = parentImgs[i];
let div = document.createElement('div');
div.innerHTML = text;
img.parentNode.appendChild(div);
let svg = div.firstChild;
img.parentNode.appendChild(svg);
// makes the SVG inherit the class from its parent
svg.classList = img.className;
// removes the junk we don't need.
div.remove();
img.parentNode.removeChild(img);
})
})
.catch((error) => {
console.log(error);
})
};
Otherwise, I came across this on Twitter today
https://twitter.com/chriscoyier/status/1124064712067624960
and applying this CSS to a div allowed me to make a colourable svg icon that can be stored in a CDN
.icon-mask {
display: inline-block;
width: 80px;
height: 80px;
background: red;
-webkit-mask: url(https://cdnjs.cloudflare.com/ajax/libs/simple-icons/3.0.1/codepen.svg);
-webkit-mask-size: cover;
}
Browser support isn't perfect yet though.
Hope this helps someone 😄
for cache you can try HTML5 app cache
https://www.w3schools.com/html/html5_app_cache.asp

Mobile iOS - Fixed background image solution

I know similar issues have been asked several times before but I have trawled through many questions/ answers and cannot find a solution that works for my specific issue.
Basically I have a responsive website which has fixed background images - the images are 1280 x 853 px, they are applied to the html tag via the following css (which is currently a bit of a mess due to trying several solutions) -
html {
background: url(/content/images/bg_lrg.jpg) no-repeat top center fixed;
-webkit-background-size: 1024px 768px;
background-attachment: fixed;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
My idea was to apply a background size - if this worked I'd use media queries to apply relevant sizes for ipad / iphone / other.
the image currently appears huge in iOS devices - as it is constraining itself to the height of the document rather than the viewport - I know there are many issues with fixed backgrounds in mobile Ios - does anyone have a workaround solution? where my image could cosntain to viewport width not document height?
First Solution, have you tried setting your ViewPort? In the head of your HTML, you can include this:
<meta name="viewport" content="width=device-width, initial-scale=1">
I would first try that. You can even specify the width for iPhones. This is the best solution at first in order to get your device to display the size of the image properly on your phone. Here is a link with a quick description of what you can do with ViewPorts:
Many sites set their viewport to "width=320, initial-scale=1" to fit precisely onto the iPhone display in portrait mode. Using the viewport meta tag to control layout on mobile browsers
Secondary Solution:
If that doesn't work, I created a modified this custom solution before these new feature came out. I modified this function to make the background of a website always fill the background regardless of screen size:
JavaScript using JQuery:
//Resize background image function
$(function () {
var $window = $(window);
var width = $window.width();
var height = $window.height();
setInterval(function () {
//Checks for screen resize every hundreth of a second and resizes elements based on that new screen size
if ((width != $window.width()) || (height != $window.height())) {
//resets the variables to prevent glitching
width = $window.width();
height = $window.height();
//calls resizing functions
resizeBg();
}
}, 100);
});
And it calls this function:
function resizeBg() {
var theWindow = $(window),
$bg = $("#bgVideo"),
aspectRatio = 1920 / 1080; //-- This is the aspect ratio (width / height) of the background image. if the video changes size.
//actually apply aspect ratio
if ((theWindow.width() / theWindow.height()) < aspectRatio) {
$bg.removeClass().addClass('bgheight');
} else {
$bg.removeClass().addClass('bgwidth');
}
}
In my CSS I have the following classes:
.bgwidth {
width: 100%;
}
.bgheight {
height: 100%;
}
And on your HTML, you want to have something like this:
<video id="bgVideo".....
OR
<img id="bgVideo"...
and I have the following CSS for my background ID:
#bgVideo {
position: fixed;
top: 0;
left: 0;
z-index: 1;
}
I hope this helps.

load image asynchronous

If I have an image tag like the following:
<img src="myimage.jpg" />
and if I add "async" to it:
<img async src="myimage.jpg" />
will the image load asynchronous?
The way to async load (lazy load) the content is to not set the 'src' attribute and then execute a script that loads the images once DOM-ready is launched.
<img data-lazysrc='http://www.amazingjokes.com/images/20140902-amazingjokes-title.png'/>
and with jQuery (or possible with plain JavaScript too) use below code (as suggested here):
<script>
function ReLoadImages(){
$('img[data-lazysrc]').each( function(){
//* set the img src from data-src
$( this ).attr( 'src', $( this ).attr( 'data-lazysrc' ) );
}
);
}
document.addEventListener('readystatechange', event => {
if (event.target.readyState === "interactive") { //or at "complete" if you want it to execute in the most last state of window.
ReLoadImages();
}
});
</script>
var img = new Image(),
url = "myimg.jpg",
container = document.getElementById("holder-div");
img.onload = function () { container.appendChild(img); };
img.src = url;
This would start loading an image as soon as you request it in-script, and whenever the image was done loading, it would grab and add the image to it.
There are lots of other ways of doing this...
This is just a dead-simple example of async loading of a single image.
But the moral is this:
For async loading to work, either load it in JavaScript and use the onload, or include the image tag on the page, without the src attribute (specify the width and height in HTML), and go back at some point, in JS, and set the image URL.
The modern way to do this is with the loading attribute for images and iframes.
Attribute: loading=lazy
This will defer loading of the content until the element reaches a calculated distance from the viewport (that just means, it's got quite likely that the user will scroll it into view).
<img src="defer.png" loading="lazy" alt="An Awesome Image" width="500" height="400">
Setting the attribute to lazy invokes the new behaviour.
This is already in Chromium since v76, but might not hit non-Chromium browsers until it goes through the usual specification shennanigans.
If you are going to defer loading using a script, it would be worth writing the image with the lazy attribute and polyfilling the behavior as opposed to working off of a class name, etc. That way, you can allow the native version to take over as it becomes available.
Forced Eager Loading
Automatic lazy loading may become a feature of lightweight browsing, in which case, you may want to do the inverse and force an image to load. You can use the same loading attribute with a value of eager to ask the browser to grab the image even if it might otherwise choose not to.
<img src="defer.png" loading="eager" alt="An Awesome Image" width="500" height="400">
Further reading
View the pull request for the WHATWG spec
Fallback JavaScript with notes about perhaps not using fallbacks
An alternate way to async load an image is by using Promise in javascript, which serves the purpose of doing things asynchronously.
function asyncImageLoader(url){
return new Promise( (resolve, reject) => {
var image = new Image()
image.src = url
image.onload = () => resolve(image)
image.onerror = () => reject(new Error('could not load image'))
})
}
// then use it like this
var image = asyncImageLoader(url)
image.then( res => {
console.log(res)
})
<img async src="myimage.jpg" />
The image tag doesnt supports any async attribute.
http://www.w3.org/TR/html5/embedded-content-0.html#the-img-element
While several other answers highlight ways to fetch images asynchronously, it may also be helpful to know that the <img /> tag supports an attribute that serves as a hint to the browser that may result in images being be decoded asynchronously. It doesn't appear to be supported by Internet Explorer.
<img src="myimage.jpg" decoding="async"/>
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Img#attr-decoding
https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decoding
https://github.com/whatwg/html/issues/1920
If you're using jQuery, I did something simple, yet effective, like this:
HTML
<div data-lazy-load-image="/Images/image-name.png" data-image-classname="pop-in"></div>
JavaScript
$(function () {
$("[data-lazy-load-image]").each(function (index, element) {
var img = new Image();
img.src = $(element).data("lazy-load-image");
if (typeof $(element).data("image-classname" !== "undefined"))
img.className = $(element).data("image-classname");
$(element).append(img);
});
});
CSS
#-webkit-keyframes pop-in {
0% { opacity: 0; -webkit-transform: scale(0.5); }
100% { opacity: 1; -webkit-transform: scale(1); }
}
#-moz-keyframes pop-in {
0% { opacity: 0; -moz-transform: scale(0.5); }
100% { opacity: 1; -moz-transform: scale(1); }
}
#keyframes pop-in {
0% { opacity: 0; transform: scale(0.5); }
100% { opacity: 1; transform: scale(1); }
}
You could extend this to include additional optional attributes for each image, but you get the idea.
This will wait until the DOM is ready, then dynamically (async) load the images into the element that you mark with the data-lazy-load-image attribute. I included the CSS to make the images "pop in" when they are loaded.
While #Norguard's example is quite simple and easy enought for an image or two, I have found echo.js pretty handy for lazy-loading, https://github.com/toddmotto/echo.
It does lazy-loading images with data-* attributes and comes with some neat other things too.
<img data-echo="img/photo.jpg">
<script src="dist/echo.js"></script>
<script>
echo.init();
</script>
I have used the following approach with jQuery.
First, don't use a "src" attribute in the image tag, but put your source into a different attribute, like this:
<img async-src="/mydirectory/myimage.jpg" />
Then, within the jQuery document-ready function, I use this code to copy the element's async-src to the element's actual src:
$("img[async-src]").each(function(index) {
$(this).attr("src", $(this).attr("async-src"));
});
Notes:
jQuery's .each function may process the tags in the sequence they are coded in the HTML/DOM, but image sizes and network issues may mean that images don't actually load sequentially. In other words, your third async-src image might visually appear onscreen before the first has finished loading.
If your page layout relies on the pixel dimensions of that image file — e.g. you're not defining the image's dimensions via tag attributes, CSS, or a parent element — then you may have to use a "src" attribute on the original file pointing to a blank white or clear GIF of the dimensions you want.
Finally, if you want to process some code after the async loading of the image — for example, to handle a fading effect or change a CSS tag relevant to the element — expand the jQuery like this:
$("img[async-src]").each(function(index) {
$(this).load(function() {
// code to run after loading
});
$(this).attr("src", $(this).attr("async-src"));
});
It might be too late of an answer but recently was facing the same issue and the "lighthouse" in the console suggested that I should follow what's mentioned here in the link:
enter link description here
Basically, I did the following as suggested and it works really well:
<script src="lazysizes.min.js" async></script>
<!-- Images End -->
</body>
You may download the lazysizes.min.js from https://raw.githubusercontent.com/aFarkas/lazysizes/gh-pages/lazysizes.min.js
and source it locally.
Then, add the class lazyload to images that should be lazy loaded. In addition, change the src attribute to data-src.
For example:
<img data-src="images/flower3.png" class="lazyload" alt="">
You may be wondering why it is necessary to change the src attribute to data-src. If this attribute is not changed, all the images will load immediately instead of being lazy-loaded. data-src is not an attribute that the browser recognizes, so when it encounters an image tag with this attribute, it doesn't load the image. In this case, that is a good thing, because it then allows the lazysizes script to decide when the image should be loaded, rather than the browser.
Visit the reference for better understanding.
Hopefully it'll be of help to someone :)
You can read more about lazyload attribute:
<img src="myimage.jpg" alt="some description" lazyload/> - with default values
or you can prioritize:
<img src="myimage.jpg" alt="some description" lazyload="1"/>
<img src="myimage.jpg" alt="some description" lazyload="2"/>