Avoid downloading images on mobile - javascript

I'm working on a responsive website where all viewport versions share the same HTML/CSS. The problem is that I don't need all images from the desktop version displayed on the mobile version. I hide those elements with display: none in my CSS.
Nevertheless the browser downloads those images because the HTML gets parsed before CSS layout happens. But I just want to download the images which I need for the mobile version so I can reduce HTTP requests and the overall download size.
A solution for me was to use the <picture> element like this:
<picture>
<source srcset="image.jpg" media="(min-width: 992px)">
<img src="" alt="an image">
</picture>
The image will not download when the browser window width < 992px because I let the fallback source attribute empty src="". Unfortunately Safari doesn't support it yet. Therefore I don't want to use it.
Now I came up with my own JavaScript/JQuery stuff but I'm not sure if it's a good idea.
HTML:
<img src="" alt="img" data-device="mobile" data-src="img-mobile.jpg">
<img src="" alt="img" data-device="tablet" data-src="img-tablet.jpg">
<img src="" alt="img" data-device="desktop" data-src="img-dektop.jpg">
JavaScript:
function loadImages() {
var mobile = window.innerWidth < 768;
var tablet = window.innerWidth >= 768 && window.innerWidth < 992;
var desktop = window.innerWidth >= 992;
if(mobile) {
$('[data-device]').each(function() {
if($(this).attr('data-device') === 'mobile') {
$(this).attr('src', $(this).attr('data-src'));
}
}); // end each
} else if(tablet) {
$('[data-device]').each(function() {
if($(this).attr('data-device') === 'tablet') {
$(this).attr('src', $(this).attr('data-src'));
}
}); // end each
} else if(desktop) {
$('[data-device]').each(function() {
if($(this).attr('data-device') === 'desktop') {
$(this).attr('src', $(this).attr('data-src'));
}
}); // end each
}
}
$(document).ready(function() {
loadImages();
});
$(window).resize(function() {
loadImages();
});
The browser parses the HTML with empty src attributes. After the page finished loading, loadImages() will be called.
For example, if the browser width is < 768px. The function iterates through all elements with a data-device attribute. It will check the data-device value and if it's mobile it will take the value from the data-src attribute and puts it as a value to the actual image src attribute.
This means that the browser will just download and display the images for the mobile version of my site.
However, I don't like this. It looks like hacked together to get around this problem somehow. I mean there must be another solution to this because I'm sure that everybody who works with responsive sites will soon or later run into the same issue. I have googled this problem a lot but I haven't found a satisfying solution yet. Everybody is saying something different.
How you guys are tackling this problem? What is the best practice?

I must say that your idea to workaround the issue looks good.
Just another idea, how about replacing the img element for a div element and load a background-image using the #media styles in css for each device? That will load one or another image depending on which device is used, and I believe that is something lots of developers use these days.
Hope that helps!

Related

Load images only for devices with > 640px screen

I have image that should be seen on desktop screens, but not on mobile.
I know that CSS media queries are designed only for displaying purposes, which means that on mobile device, image will still be loaded but just not displayed.
Is there a way to prevent image from loading on devices with <640px resolution?
You can check the width of the page on load, and based on that set the src attributes on the images if required.
if(window.innerWidth > 600) {
document.getElementById("img1").src = "//placehold.it/150";
} else {
alert("No image loaded");
}
<img id="img1" src="" />
Now, a concern might be that this merges the UI logic (i.e. the URL of the image) into JS. You can avoid that by using a data attribute such as data-src to keep the actual image src and set it dynamically to src based on window.innerWidth. Something like the following:
if(window.innerWidth > 600) {
var img = document.getElementById("img1");
img.src = img.attributes["data-src"].value;
} else {
alert("No image loaded");
}
<img id="img1" src="" data-src="//placehold.it/150" />
window.onload = function(){
if(document.body.clientWidth> 600){
// . . . code . . .
}
}
With pure CSS, you can't.
You have two options:
Option 1: HTML5
If you don't need to support old browsers, you can use HTML5 new tag <picture>. Like so:
<picture>
<source
media="(min-width: 641px)"
srcset="images/my_desktop_image.png">
<source
media="(min-width: 451px)"
srcset="images/my_mobile_image.png">
<img
src="images/my_default_image.png"
alt="picture text">
</picture>
Option 2: Javascript (might be easier with jQuery library)
With jQuery, you can detect window size, and based on that load the desired image:
$(window).resize(function() {
if($(this).width > 640) {
// load image..
}
});

How to get proper photo (PHP) depending on screen size?

I have some issues with page speed depended on images that I get from server and just want to know if it is possible to get different file according to screen that page is displayed on. I found
if( typeof( window.innerWidth ) == 'number' ) {
//Non-IE
xx = window.innerWidth;
yy = window.innerHeight;
} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
//IE 6+ in 'standards compliant mode'
xx = document.documentElement.clientWidth;
yy = document.documentElement.clientHeight;
} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
//IE 4 compatible
xx = document.body.clientWidth;
yy = document.body.clientHeight;
}
That is possibly providing variable for later use, mainly I am focused on aspect if it is possible to get different img size througt
{php} $x=1; $this->assign('varX',$x); {/php}
{foreach from=$offer->GetPhotos() item=photo}
{if $varX ==1}
{assign var="fotourl" value=$photo->GetImgSrc('253_161', false, false, false)}
<div class="item active">
<a href="oferta.html?id={$offer->GetId()}">
<img alt="Front view of the house." class="lazyload img-responsive wp-post-image" data-original="{$photo->GetImgSrc('253_161', false, false, false)}" height="161" src="{$photo->GetImgSrc('253_161', false, false, true)}" width="253"></a>
</div>
{else}
<div class="item lazy-load-item">
<a href="oferta.html?id={$offer->GetId()}">
<img alt="Luxury Villa In Rego Park" class="img-responsive" data-lazy-load-src="{$photo->GetImgSrc('253_161', false, false, true)}"></a>
</div>
{/if}
{php} $x=$x+1; $this->assign('varX',$x); {/php}
{/foreach}
I want to achieve moment when I can get different size of photo for desktop and mobile
Thank You in advance
What you're looking for is called 'responsive design'; that is, as site where the page adapts to the size of the browser window. It's a very common requirement, and involves a lot more than just adapting the image sizes. But image size is one aspect of it.
In today's internet, you should not need to do any server-side scripting at all in order to achieve a good responsive design.
Page layout can adapt dynamically to screen size by the use #media blocks in your CSS. This is the most common thing people think of when talking about responsive design.
Image file sizes (the bit you're asking about) can be made responsive by use of two relatively new HTML features: scrset and the picture element.
scrset is a new attribute for the existing <img> tag. It allows you to specify different image files for the element, and for the browser to chose the most appropriate one based on the screen size. You would use it like so:
<img src="default-size.jpg" srcset="medium-size.jpg 1000w, large-size.jpg 2000w">
You can read more about srcset here.
The picture element is more complex. It does much the same thing, but allows the developer much more control over exactly which image is displayed, rather than leaving it to the browser. An example:
<picture>
<source srcset="smaller-image.png" media="(max-width: 800px)">
<img src="default-image.png">
</picture>
In this example, you are telling the browser to use the smaller image when the page is viewed in a small browser window less than 800 pixels wide, eg maybe on a mobile device. You're being more explicit about it than the plain srcset example.
Find out more about the picture element from MDN.
Note that both of these HTML features are relatively new, and thus may not be supported on older browsers. However they have been supported long enough to be in place for the majority now, and both of them have a graceful fallback of defaulting to the main image in the <img> tag if they aren't supported by the browser. Thus your IE9 user will just see the original base image regardless of his screen size; but it will at least work for him at that level.
So in summary, you should not need any PHP code for this, nor any JavaScript code. Just learning a few new bits of HTML.
[Edit] Regarding the browser support point I mentioned above, #FodorZoltán suggested that I link to the compatibility tables:
http://caniuse.com/#search=picture
http://caniuse.com/#search=srcset
This can be only handled on client-side by javascript: (the second aproach is cleaner)
Get your different sized image paths from PHP into JS
var images = { 'image1ID' : {large: '{$image1largepath}', small: '{..}', ..}, 'image2ID': .. };
On document load get the size of the screen in JS
Loop the images array above, get the element by id(which is the key in the array), and update src attribute according to the screen size
Another way would be by setting attributes on your images: img-dynamic, large-src='', small-src='' etc. and runing a function in JS that would get the size of the screen, get all img elements with this img-dynamic and set their src attributes value to the large-src or small-src value according to size.
var windowH = 800, windowW = 1000;
/* First get window sizes */
function setDynamicImagePaths(to){
var imgs = document.querySelectorAll('img[img-dynamic]');
for(var i = 0, l = imgs.length; i < l; i++){
imgs[i].src = imgs[i].getAttribute(to);
}
}
/*
When your sure that the img elements are loaded
ex: onload or at the end of the body
call this
*/
window.onload = function(){
if(windowH > 700 && windowW > 900)
setDynamicImagePaths('src-large');
else
setDynamicImagePaths('src-small');
}
<img img-dynamic width='100' height='100' src-small='noimgpath' src-large='https://pixabay.com/static/uploads/photo/2015/10/01/21/39/background-image-967820_960_720.jpg'/>

Responsive background images

Currently I'm working on building a solution for having responsive background images set via JavaScript. I am using Picturefill to create cross-browser support.
What do I need? There is an element on my page which needs a pretty little background photo. On the page there is a picture element which loads conditionally images. However I specified one default image source if the browser doesn't have proper picture element support.
With MooTools I check what photo is supposed to show up on domready, on window resize I check my image 'src' again to replace my current picture if needed (with a bigger or smaller one).
In FireFox the picture element replaces the image 'src' in the DOM, it works perfect!
Chrome (and IE) don't replace the image 'src' so my photo will always have the default photo dimensions according to MooTools. However, when you hover over the image 'src' via the Chrome developer tools it does show the correct image source for that media query.
I can get in way too many details but trust me I really need to do it like mentioned above, who want to help me with this? :)
<script>
var Placeholder = $('Placeholder');
var CoverImage = $('MyCover').getElement('img').src;
Placeholder.setStyle('background-image', 'url(' + CoverImage + ')');
var $timer = null;
window.addEvent('resize', function(){
var ResponsiveImage = function(){
var $ResponsiveImage = $('MyCover').getElement('img').src;
$('Placeholder').setStyle('background-image', 'url(' + $ResponsiveImage + ')');
};
clearTimeout($timer);
$timer = ResponsiveImage.delay(250, this);
});
</script>
<picture>
<source media="all and (max-width: 30em)" srcset="1.jpg">
<source media="all and (min-width: 30.063em) and (max-width: 48em)" srcset="2.jpg">
<source media="all and (min-width: 48.063em) and (max-width: 80em)" srcset="3.jpg">
<source media="all and (min-width: 80.063em)" srcset="4.jpg">
<img src="2.jpg">
</picture>
Thanks for the possible solutions, I am very grateful!
Cheers,
Stefan
Perhaps I don't understand exactly what you are trying to do, but instead of trying to use the script to control the dimensions why not use the CSS property background-size: cover; instead? That is what I always use for responsive background images not that it is widely supported by browsers.
You should really look at http://foundation.zurb.com/docs/components/interchange.html.
Maybe you can get the script and adapt it to your case?
First of all your markup:
In picture land you don't need to use min-width and max-width. The first source, that matches is the media query is used:
<picture><source media="(max-width: 30em)" srcset="1.jpg">
<source media="(max-width: 48em)" srcset="2.jpg">
<source media="(max-width: 80em)" srcset="3.jpg">
<source srcset="4.jpg">
<img src="2.jpg"></picture>
Now, what you need is actually the property currentSrc, but be aware it needs to be handled different than the src property, because it is updated, after the image is loaded (so don't use resize, use load).
Fortunately there is already a simple lazySizes plugin called bgset, that does exactly what you need. Here you find a demo and here you find the documentation. Of course you can also check out the source code and build your own.
In case you want to use the plugin your markup changes to something like this:
<div class="lazyload" data-bgset="1.jpg [(max-width: 30em)] | 2.jpg [(max-width: 48em)] | 3.jpg [(max-width: 80em)] | 4.jpg"></div>
I am using the currentSrc property to get the updated image source and it works like a charm! Thanks everyone for the help!

Different size images in website depending on screen resolution

I have a website with some images, and for this the page loading can be slow on mobile devices that have only mobile internet connection.
So, my question is: assign different images, smaller or bigger depending on device, when page is loaded could be a solution?
Example
Initially my img in the dom could be:
<img src="" id="img1" alt="img1" />
And then, adding a script in head:
$(document).ready(function () {
loadImg();
})
The loadImg function can be like:
if((window.screen.availHeight < 1234)&&(window.screen.availWidth < 1234))
document.getElementById("img1").src = "small";
else
document.getElementById("img1").src = "big";
Try this js library https://github.com/scottjehl/picturefill
I don't know how this affects the SEO, though.

JS / jQuery : background image onload

I have function that is supposed to wait till background image is loaded and then add image's ratio to it's container and fade background image container in. It seems to work in Chrome, but fails in Internet explorer 8 and 9, and not always works in 10. In ie8 it doesn't seem to understand jquery on('load') event. In ie 9 and 10 it not always finds width of background image. How can I make it work in ie8+ and other major browsers?
js:
$('.item').each(function(index) {
var thisItem = $(this);
var image_url = thisItem.find('.img').css('background-image');
var img = new Image();
img.src = image_url.replace(/(^url\()|(\)$|[\"\'])/ig, '');
if (image_url){
//initialize only when background img is loaded
var $img = $('<img>').attr('src', img.src).on('load', function(){
//don't allow img to be larger than it is
if(img.width < thisItem.width()){thisItem.css({'max-width':img.width+'px'});}
var ratio = img.height/img.width;
thisItem.find('.item_ratio').css({'padding-bottom':ratio*100+'%'});
thisItem.find('.img').fadeIn(800);
});
}
});
html:
<div class="item">
<div class="img" style="background-image:url('some_url'); width: 100%; background-size: cover;"></div>
<div class="item_ratio"></div>
<!-- Some other not important html ->
</div>
The load event on images has been shown to be unreliable/absent, which is why there's a well-known jQuery plugin to help smoothen things out cross-browser. I'd recommend having a look at that instead rather than trying to figure out the browser issues and edge cases like missing load events when browsers fetch images from cache etc.
Edit: code sample to make it work with a dangling <img/> (untested)
//initialize only when background img is loaded
var $img = $('<img>').attr('src', img.src).prependTo(thisItem).hide().imagesLoaded(function() {
//don't allow img to be larger than it is
//... [your code]
});
I used this approach here. (The thumbs on the left are a single background image sprite, I animate those in once the image has loaded).
As an aside, you may also be able to use background-size: contain in CSS. Doing that might be more performant in newer browsers (if images are large) and much simpler since you don't need any code. It's unsupported in IE8 though, which you can test if you're using Modernizr. That would probably be my preferred approach, but I normally include Modernizr anyway. YMMV.

Categories

Resources