Lazy loading images how - javascript

I am developing an eshop .At products page based on category i putted some javascript based filtering. However a problem arises if a category has a lot of products.
This link has something similar i do ...
http://www.snowandrock.com/sunglasses/snowboard/fcp-category/list?resetFilters=true
How ever this page is painfully slow and is over 2mb !!!
Every product for me needs half killobyte but the image is the problem..
So i am looking how to lazy load images..
Since my page has pagination unlike that site i think that loading images that are visible only to the page is a solution.The probem however is how to do it in order to work both for javascript and non javscript enabled people..
The only solution i though is storing the link at the css class somehow of the image for the non visible products and if shown after filtering change via javascript the image src...
Non javascript users dont have this problem as clicking on a filter would navigate them to other page...
Any other idea?

Four options:
Here are three options for you:
Use a background image
Kangkan's background answer has this covered.
If that doesn't work for you, I'm assuming you only need help with the JavaScript-enabled stuff, since you said the non-JavaScript users will see a different page.
Use a plug-in
Paging has been done. You've said in a comment that you're using jQuery. There are lots of jQuery plug-ins for paging. Find one you like, and use it. They will be of varying quality, so you'll want to test them out and review their code, but I'm sure there's a decent-quality one out there.
Server-side Paging
This is where the main page loads either without any products at all, or with only the first page of products. Typically you'd put all of the products into a container, like this:
<ul id='productList'>
</ul>
Then you'd have the usual UI controls for moving amongst the pages of results. You'd have a server-side resource that returned HTML snippets or JSON-formatted data that you could use to populate that list. I'll use HTML for simplicity (although I'd probably use JSON in a production app, as it would tend to be smaller). Each product entry is its own self-contained block:
<li id='product-001'>
<div>This is Product 001</div>
<img src='http://www.gravatar.com/avatar/88ca83ed97a129596d6e8dd86deef994?s=32&d=identicon&r=PG'>
<div>Blurb about Product 001</div>
</li>
...and then the page returns as many of these as you think is appropriate. You request the page using Ajax and update the product list using JavaScript. Since you've said you use jQuery, this can be be trivially simple:
$('#productList').load("/path/to/paging/page?start=X&count=Y");
Here's an example prototype (not production code); it fakes the Ajax because JSBin was giving me Ajax issues.
One big page download, then client-side JavaScript paging
I'm not sure how you're doing your filtering, but if you have an element that contains the product information, you can store the image URL in a data-xyz attribute on it:
<div id='product-123' data-image='/images/foo.png'>
Then when your code makes that visible, you can easily add an img to it:
var prod, imgsrc, img;
prod = document.getElementById('product-123');
prod.style.display = 'block'; // Or whatever you're doing to show it
imgsrc = prod.getAttribute('data-image');
if (imgsrc) {
img = document.createElement('img');
img.src = imgsrc;
prod.appendChild(img); // You'd probably put this somewhere else, but you get the idea
prod.removeAttribute('data-image');
}
Edit In a comment elsewhere you said you're using jQuery. If so, a translation of the above might look like this:
var prod, imgsrc, img;
prod = $('#product-123');
prod.show();
imgsrc = prod.attr('data-image');
if (imgsrc) {
$("<img/>").attr('src', imgsrc).appendTo(prod); // You'd probably put this somewhere else, but you get the idea
prod.removeAttr('data-image');
}
No need to remove it again when hiding, since the image will already be shown, which is why I remove the attribute once we've used it.
The reason I've used the data- prefix is validation: As of HTML5, you can define your owwn data-xyz attributes and your pages will still pass validation. In earlier versions of HTML, you were not allowed to define your own attributes (although in practice no major browser cares) and so if you used your own attribute for this, the page wouldn't validate.
References (w3.org):
Embedding custom non-visible data with the data-* attributes
getElementById
createElement
getAttribute
removeAttribute
appendChild
Off-topic, but a lot of this stuff gets a lot easier if you use a JavaScript library like jQuery, Closure, Prototype, YUI, or any of several others to smooth over the rough edges for you. (You've since said you're using jQuery.)

If you simply wish to load the images slowly and the rest of the page gets loaded first, you can put the images as background and not use the <img> tag. If you use the <img> tag, the image is loaded at the time of loading the page and so the page load becomes slow. However, the background images loads after the page is shown to the user. The user can read the text and see the images loading after some time.

I'm fairly certain it's not possible in plain HTML without some kind of Javascript intervention.
After all, if it was possible to do it without scriping, why would anyone have implemented it in Javascript in the first place?
My question is: How many visitors do you get who these days don't have Javascript enabled? I bet it's very few. And in any case, those people are used to sites not being fully functional when they have javascript disabled; your site will actually be better than most if the only difference they have to put up with is slower loading speed.
(ps - I presume you're using Jquery's LazyLoad plugin for the Javascript enabled people?)

I'd suggest to implement responsive image approach in order to avoid huge image files on devices which cannot display it properly (or human can't tell the difference).

I wrote the following code for my own site. I used JQuery:
1. Name all classes, where U want lazy loading by the same name, say "async"
2. Copy the real image location from 'src' to 'alt' attribute
3. After finishing page loading my script will copy all 'alt' values into 'src'
Look at example. This is full working sample html:
<html>
<head>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('img.async').each(function(i, ele) {
$(ele).attr('src',$(ele).attr('alt'));
});
});
</script> </head> <body> <img class="async" title="Гороскопы" alt="http://virtual-doctor.net/images/horoscopes.jpg" width="135" height="135"/>
</body>
</html>
You can feel the speed in real site, where I used it
http://virtual-doctor.net/

Browser level support
Modern browsers have the ability to load images lazy using loading="lazy" attribute!
<img src="image.png" loading="lazy" alt="…" width="200" height="200">
For more information, visit here.

EDIT: I reread your question & noticed you also want this to work for people with Javascript disabled! Then yes my answer is not acceptable - but I'll leave it for the record.
Here are some Javascript libraries for Image Lazy Loading.
They help you load the images needed when the elements 'would' be in view by simply changing the image src attribute.
github.com/toddmotto/echo and toddmotto.com/echo-js-simple-javascript-image-lazy-loading : plain JS, IE8+, 2KB, only 5 contributors github.com/toddmotto/echo/graphs/contributors
github.com/dinbror/blazy/ and dinbror.dk/blog/blazy - plain JS, IE7+, 1.2KB (minified and gzipped), only ONE contributor github.com/dinbror/blazy/graphs/contributors
github.com/tuupola/jquery_lazyload and www.appelsiini.net/projects/lazyload : jQuery dependency, MIT License, tested with Safari 5.1, Safari 6, Chrome 20, Firefox 12 on OSX & Chrome 20, IE 8 & IE 9 on Windows, Safari 5.1 on iOS 5 both iPhone and iPad. 18 contributors https://github.com/tuupola/jquery_lazyload/graphs/contributors
github.com/luis-almeida/unveil and luis-almeida.github.io/unveil - special: lightweight version of Lazy Load github.com/tuupola/jquery_lazyload : IE7+, jQuery dependency, MIT License, 5 contributors https://github.com/luis-almeida/unveil/graphs/contributors
github.com/shprink/BttrLazyLoading and bttrlazyloading.julienrenaux.fr - special: dedicated for responsive designs : jQuery dependency, IE9+, MIT License, 3KB (minified & zipped), 5 contributors github.com/shprink/BttrLazyLoading/graphs/contributors
Important: I am still investigating which of these Javascript libraries is best to use. Do your homework I'd say, take some time to search what's the best tool for the job. My requirements are usually: license, dependencies, browser support, device support, weight, community, and history.

Related

Best practice for browser specific content

I'm working on a project where I need to show specific content & include a file for a specific set of browsers.
I'm starting off with IE.
Since IE10 conditional comments aren't a thing anymore I'm trying to figure out what the best practice is for including specific content and a specific javascript file with some general fixes for things like css variables aswell.
So far I got something for just "exclusive" JS code but, I only want the file to be included based on what browser is being used.
if (/Edge/.test(navigator.userAgent) || /rv:11.0/i.test(navigator.userAgent)) {
document.write('<script src="./js/app-legacy-browsers.js"></script>');
}
Other than that I need to show the active browser icon on the site with some pre-set content.
I'd like to accomplish the same result as if
<!--[if IE]><![endif]--> still existed.
Main reason of not wanting to use the if statement is not wanting to affect pagespeed on first load.

How to combine good result with google page speed and putting css on bottom of the page?

I am trying to get good results for pageSpeed with google on my page.
I got good results but putting CSS and JS on bottom of the page.
But I got the problem: my page renders without CSS, then got rendered normally after css is loaded (it produces like a page flash)
I tried to solve by putting style on body display: none
then added the jquery document.ready and put display to normal, but my google page speed results went down again.
Is there a solution/tip to get good pageSpeed results with good rendering of the page.
Unfortunately with HTTP/1 we are forced to bundle all our css rule-sets into one file to prevent multiple resource requests, this won't be the case with HTTP/2.
Speed is definitely something you would want to improve in a website, but the important point here is how fast useable content is in front of the visitors. The resources you use will eventually increase in size, this shouldn't be proportional to the time the user waits to be able to use the page. Focus on perceived performance.
What is the current problem with CSS files located in the head tag?
A: They block rendering until the file is loaded.
What can you do about it?
There is a specification that involves the preload keyword used in the link tag to load css files asynchronously.
This specification defines the preload keyword that may be used with
link elements. This keyword provides a declarative fetch primitive
that initiates an early fetch and separates fetching from resource
execution.
Source: w3
This, however, is still not fully supported by browsers. (Browser support here).
A solution is to use loadCSS which is basically a polyfill.
The new <link rel="preload"> standard enables us to load stylesheets
asynchronously, without blocking rendering, and loadCSS provides a
JavaScript polyfill for that feature to allow it to work across
browsers, as well as providing its own JavaScript method for loading
stylesheets.
Finally, the technique that is commonly proposed is the following:
Load a stylesheet with the critical css rule-sets to be able to display
information to the user, such as layout formatting, this is included as you normally would, in the head tag with <link>.
Load the stylesheet with the css rule-sets that are not critical to the initial rendering of the page which will be loaded with loadCSS.
Notes:
If you go down this path make sure to check tools like
webpagetest.org to test perceived performance.

Is it possible to convert a dynamic HTML page with a lot of javascript to a page without javascript?

I have a page with a lots of javascript. However, the page once rendered remains static, there are no moving things or special effects, etc... It should be possible to render the same HTML without any javascript at all using only the plain HTML and CSS. This is exactly what I want - I would like to get a no javascript version of the particular page. Surely, I do not expect any dynamic behavior, so I am OK if buttons are dead, for example. I just want them rendered.
Now, I do not want an image. It needs to be an HTML with CSS, may be embedded with the HTML, which is fine too.
How can I do it?
EDIT
I am sorry, but I must have not been clear. My web site works with javascript and will not work without it. I do not want to check if it works without, I know it will not and I really do not care about it. This is not what I am asking. I am asking about a specific page, which I want to grab as pure HTML + CSS. The fact that its dynamic nature is lost is of no importance.
EDIT2
There is a suggestion to gram the HTML from the DOM inspector. This is what I did the first thing - in Chrome development utils copied as HTML the root html element and saved it to a file. Of course, this does not work, because it continues to reference the CSS files on the web. I guess I should have mentioned that I want it to work from the file system.
Next was to save the page as complete with all the environment using some kind of the Save menu (browser dependent). It saves the page and all the related files forming a closure, which can be open from the file system. But the html has to be manually cleaned up of all the javascript - tedious and error prone.
EDIT3
I seem to keep forgetting things. Images should be preserved, of course.
I have to do a similar task on a semi-regular basis. As yet I haven't found an automated method, but here's my workflow:
Open the page in Google Chrome (I imagine FireFox also has the relevant tools);
"Save Page As" (complete page), rename the html page to something nicer, delete any .js scripts which got downloaded, move everything into a single folder;
On the original page, open the Elements tab (DOM inspector), find and delete any tags which I know cause problems (Facebook "like" buttons for example) (I also try to delete script tags at this stage because it's easier) and copy as HTML (right-click the <html> tag. Paste this into (replace) the downloaded HTML file (remember to keep the DOCTYPE which doesn't get copied;
Search all HTML files for any remaining script sections and delete (also delete any noscript content), and search for on (that's with a space at the start but StackOverflow won't render it) to remove handlers (onload, onclick, etc);
Search for images (src=, url(), find common patterns in image filenames and use regular expressions to replace them globally. So for example src="/images/myimage.png" => |/images/||. This needs to be applied to all HTML and CSS files. Also make sure the CSS files have the correct path (href). While doing this I usually replace all href (links) with #;
Finally open the converted page in a browser (actually I tend to do this early on so that I can see if any change I make causes it to break), use the Console tab to check for 404 errors (images that didn't get downloaded or had a different name) and the Network tab to check if anything is still being loaded from the online version;
For any files which didn't get downloaded I go back to the original page and use the Resources tab to find them and download manually;
(Optional) Cull any content which isn't needed (tracker images/iframes, unused CSS, etc).
It's a big job. I'd love a tool which automated all that, but so far I haven't found one. The pages I download are quite badly made (shops) which have a lot of unusual code, so that's why there are so many steps. You might not need to follow every step.

General questions about #! hashbang urls and am I using them correctly

I'm in the process of writing a website that includes a reasonably large gallery. First page of the gallery the user will be displayed a bunch of thumbnail images with a url of: website.com/gallery.php
When they click a thumbnail image, if javaScript is turned off it will follow the url in the href and go to a page called gallery.php?img=67. If javaScript is turned on the href click will not execute, instead it will perform an ajax request to display the larger image and some text about it. The url changes to gallery.php#!img=67. The back button will take you back to the thumbnails, pressing f5 will keep the big image displayed with the text. If someone copies the address with the #! and sends it to someone they will get the same image displayed (assuming the receiver has javaScript turned on).
My question is, have I sorted this out correctly for google to index the individual gallery pages? Will google index them twice, once with the ?img=67 and once with the #! and if so is that a bad thing? I'm using javaScript/Ajax to preload the larger images once the thumbnail page is loaded for speed. I've read a lot of backlash against using hasbang ajaxy things recently and wondering if you think can justify using it here?
Google will follow your links and index the ?img=67 pages, and will not index your #! pages, because it can't see those links. You can tell Google about those links by doing the following:
Add <meta name="fragment" content="!"> to the <head> of your document, and
Handle requests for /?_escaped_fragment_= by returning an "HTML Snapshot" of your page that has all your #! links in the <A> tags.
Also, to make the most of this feature, you should also handle requests for /?_escaped_fragment_=img=67 by returning an HTML snapshot page with the big image displayed. Remember, GoogleBot doesn't execute Javascript. Using the #! URL tells Google to retrieve an alternate version of the page (A version where #! has been replaced with ?_escaped_fragment_=) that should render without Javascript.
THe use of #! tags in URLs are in the news recently, with updates to a well known blog.
http://isolani.co.uk/blog/javascript/BreakingTheWebWithHashBangs has a good description of what they are best used for - and when they can be bad. I think your use in a gallery is quite valid.
In short, a URL like http://lifehacker.com/#!5753509/hello-world... is rewritten by Google, and other compatible web-spiders as http://lifehacker.com/?_escaped_fragment_=5753509/hello-world...
Google may index them twice, but you can also use the canonical meta-tag to ensure it knows what the 'official' copy is.
Possible solution (as suggested in http://isolani.co.uk/blog/javascript/BreakingTheWebWithHashBangs) is to use regular links and translate them to #! in the OnClick() event. This ensures that the site displays regular links and not the shitty #!.
It does mean extra work for the server though, since the server needs to support both versions (the Ajax version and the regular version), but I think it worth it.These #! are so ugly..

Load browser images with javascript event?

I've got a page containing a lot of images, which are initially hidden from view as I'm using tabbed divs (ie. hiding some divs using CSS display:none).
Therefore, when then page loads, it takes ages to load all of the images, which looks like the page is slow (as the loading bar on the browser doesn't complete for 10+ seconds).
I would like a way of not loading images until they are visible on the page.
I've played around with jQuery LazyLoad, however this only seems to load images when scrolling the browser (which doesn't work for tabbed divs).
Therefore, is there a way of changing LazyLoad to work like this, or is there a better way of doing this?
Thanks!
Maybe jQuery Tabs could do what you need, with ajax call on tabs...
How do you display your hidden divs?
One plan of attack:
Instead of putting the image URL in the src attribute of the img tag, put it somewhere else (e.g. a hidden span with a particular class above it) and when showing the div, iterate through all the img tags and set the src to the URL it should have had.
As a method it's definitely got some downsides.
If you're using (or can use) the HTML5 doctype, you can use the "data-" prefix for tag attributes:
<img src="" data-src="/path/to/image" style="display: none" />
And then you can use Javascript to fill the src with the data-src:
$(SELECTOR).attr("src", $(SELECTOR).attr("data-src"));
If your only goal is to 'hide' the progress bar which is taking so long due to the large number of images, I'd go for some kind of AJAX solution, since that way the progress bar is not 'used'. It does introduce more complexity in the way you want to load your HTML elements (and possibly when).
I personally don't like using HTML attributes for anything other than their original purpose, so storing the path in another attribute and switching when needed would not be my first option. Instead, I'd try to create a JavaScript array (id => path) and update the separate HTML IMG elements when needed.
Good luck! ;)
I have tried that lately and have to say that this is not possible with js anymore. Maybe it has never been...
Projects like lazyload have always proclaimed that they would stop all images from loading on startup, but you can see in firebug that this does not work. The images are even loaded twice, on domready and when you start scrolling...
Your only choices would be ajax on the on hand or doing something like this:
<img src="transparent.gif" alt="" rel="real image source" />
and then switch attributes when the divs become visible, so the image starts loading.
This works fine as well at least if you don't need google indexing them.
Hope that helps! :)
Edit: Hm, why did I get a -1 when I was just givin an answer? Just have a look at pages with lazyload and enable firebug and then scroll the page. It was even said here on stackoverflow and in the comments for the lazyload plugin that this is the only solution at the moment ... :(
I was unaware of this previously, but LazyLoad does support triggering from events:
http://www.appelsiini.net/projects/lazyload
If anyone needs a hand on how I did this, let me know!

Categories