I don't want to set them to display:none; with media queries because they would still load. Is there any way to load them only if the device's width is over 500px for example?
You could load them all after the page itself has loaded using javascript, and ignore certain images if window.innerWidth is less than 500.
The specifics of the implementation would be determined by your own application, but I would recommend something like the following:
Replace all images with placeholders, and give the ones you may wish to hide a certain class:
<img src="placeholder.png" class="gt500" data-source="realimage.png">
You could then do something like (assuming jQuery):
$(document).ready(function(){
if(window.innerWidth > 500) { return; }
$('img.gt500').each(function() {
$(this).attr('src', $(this).data('source'));
});
});
Which will swap all the placeholders for the real images, but only if the window is wide enough.
I'd try something like this:
<img src="" data="actualimagesource" />
Check each image, either on the server or client side: If the site's width allows the image to display, pull the string from "data" and place it in the "src" attribute.
Very similar to: http://www.appelsiini.net/projects/lazyload
You can't prevent an image from loading except to delete it from the DOM or change it's src. Even then, it'll already have started loading, so whether it loads in full will depend on how the browser implements it, and I don't know the answer to that.
All I can suggest is that you prefix all the image srcs with a #, then do something like this:
var imgs = document.querySelectorAll('img[src^="#"]');
for (var i = 0; i < imgs.length; i++) {
imgs[i].setAttribute('src', imgs[i].getAttribute('src').substr(0));
}
if the screen width is greater than a certain number. That prevents users who have JavaScript disabled from seeing your images though, so consider the pros and cons carefully.
I'd probably do this server-side. WURFL is a database that's often used for mobile device sniffing, a PHP example is here. In desktop web development browser and device sniffing is considered super bad practice. For mobile, because of the sheer number of devices and their different capabilities it's often a necessity. I believe WURFL tests the user agent string server side (amongst other things) to detect the device and will then return a bunch of information about it (including screen resolution) you could then serve different sized images based on this information.
I don't think there's a way of cleanly preventing image load at the front-end. You could loop through all images with javascript on document load and set the src attribute to an empty string if their width was greater than 500px. The problem with this is that you'd have to make sure that all your images had specific dimensions in the markup and even then some browsers won't report the width until the image has finished loading. You also couldn't guarantee that images wouldn't start download before the javascript kicked in (and not all mobile devices support js or have it turned on) This feels horribly hacky to me though.
Related
A blog post I recently read suggested setting the sizes attribute of <img> tags automatically, using a ResizeObserver.
This would mean that at different image widths (in practice usually different breakpoints) the sizes would update each time the image resizes.
Imgix is doing something similar, and they state:
The sizes attribute was designed to give the break-points information to the browser as early as possible, typically before the images on the page have even rendered. Because imgix.js is loaded after the page's HTML markup, the browser gets the information about sizes just a tad-bit later than usual. This means that some of the performance gains from using the sizes attribute are lost, since the browser has to wait for imgix.js to load before it can make a decision.
Is this approach useful at all? Or is it wrongly using what was intended to be a static hint at image widths?
We're currently building a website for mobile devices. Supported operating systems and browsers should be:
Android 4.x (Stock Browser, Google Chrome)
iOS6+ (Safari, Google Chrome)
In order to also support high resolution displays we evaluated various techniques and libraries to automatically replace images with their high-res pendants:
Attempt 1: retina.js
http://retinajs.com/
The first attempt was to use a normal <img> Tag like this: <img src="foo.png"> and use retina.js to let it automatically replace the src Attribute with the name of the retina image (foo#2x.png). This works but has 2 downsides: First, it will create unwanted overhead because both, the original as well as the retina image, would be loaded and second, if there is no retina image available it will cause lots of 404 errors on server log which we do not want.
Attempt 2: picturefill.js
https://github.com/scottjehl/picturefill
This framework uses some weird html markup based on <span> elements. For me it looks like as if the author tried to mimic the proposed <picture> element which is not a standard (yet), see http://picture.responsiveimages.org - I don't like this approach because of the weird markup. For me it doesn't make sense to semantically describe images with spans.
Attempt 3: Replace images via CSS property background-image
I see sometimes people using CSS media queries to detect retina displays and then set a background-image on a div (or similar element) with a higher or lower solution picture. I personally don't like this approach either because it completely discourages creating semantically good markup à la <img src="foo.png">. I can't imagine building a website just with div's and then set all images as background images - This just feels very weird.
Attempt 4: Set images via CSS property content:url(...)
As proposed here Is it possible to set the equivalent of a src attribute of an img tag in CSS? it seems to be possible to overwrite the src Attribute in img Tags via CSS using the property content:url(). Now, here is the plan: We set img tags for each image with a transparent blank 1x1 png referenced in its src attribute, like this: <img id="img56456" src="transp_1x1.png" alt="img description">. Now this is semantically ok and also valid against the W3C validator. Then we load a CSS Stylesheet that sets all the images on the website via Media Queries.
Example:
#img56456{content:url(foo.png)}
#media (-webkit-min-device-pixel-ratio: 2){
#img56456{content:url(foo#2x.png)}
}
Now, this approach works pretty good:
No overhead
Solid markup
Works on the required devices/browsers
SEO for Images is not requirement here
Now, could this approach cause any side effects we didn't think of? I am just asking because I know it works but kinda "feels" weird to set all images via CSS and I also found this comment on this approach on SO Is it possible to set the equivalent of a src attribute of an img tag in CSS?:
"Worth to add that even in browsers that support assigning content to
img, it changes its behavior. The image starts to ignore size
attributes, and in Chrome/Safari it loses the context menu options
like 'Save image'. This is because assigning a content effectively
converts img from empty replaced element to something like
<span><img></span>"
Could this be a problem? (I didn't notice any sizing problems and the context menu is not a requirement)
There are lots of advantages and disadvantages, but one disadvantage is that the image won't be cached. This is more of a problem on mobile devices where internet is generally slower and more expensive for the user (if on a data connection not wifi).
I don't know about those libraries but you could use media-queries, depending on how many images you have, otherwise it would be lots of code variations to write. And have a threshold screen size at which point you use a different file. Only one file is actually loaded, even though you specify both in the media-queries.
The new version of picturefill http://scottjehl.github.io/picturefill/ doesn't rely on <span> any more. Instead it simply uses the official HTML5 srcset attribute and mimics its behavior if the browser doesn't support it, so for me this is the ideal solution after quite a while now.
Using the CSS property content:url(...) was a neat little idea but it made things a little complicated and hackish too.
So, to answer my own question: No, it's a bad idea. Using the new version of picturefill is a way better solution. You can even remove it after a while when newer versions of all major browsers support the srcset attribute and you'll still be standard compliant. http://caniuse.com/#search=srcset
Example:
<img srcset="examples/images/small.jpg, examples/images/medium.jpg 2x" alt="A giant stone face at The Bayon temple in Angkor Thom, Cambodia">
<script src="picturefill.js"></script>
I'm trying to swap out my image sources dependant on the window size and pixel density- To prevent mobiles loading extra large images while still serving full res images to things like retina macbooks with huge screens.
I've got an img elemnt looking like this:
<img class="projectimg responsivize" src=mobile.jpg data-mobile-x2=mobile-retina.jpg data-tablet=tablet.jpg data-tablet-x2=tablet-retina.jpg data-full=desktop.jpg data-full-x2=desktop-retina.jpg />
I'm using vanila javascript(don't want to wait for lidbaries to load) below(WIP, needs screen size testing, just swaps out for the full size image at the moment)
var toresponsive = document.getElementsByClassName("responsivize");
for (var i=toresponsive.length -1; i >= 0;i--){
toresponsive[i].setAttribute('src',toresponsive[i].getAttribute('data-full'));
}
This is working fine- My question is about the placement- If I put it in the head then it runs before the browser can see the image tags. If I put it at the end of body, The browser GETs all the small image sources- doubling the number of http requests for non-mobile screens.
Is there a way to have the browser not GET the images until the javascript has run, while leaving a values in the src attribute of the img tags so I have support for systems not running javascript?
Ive mobile optimised my site with media queries. Everything looks how I would like it to but unnecessary images (as they're hidden with css) are being downloaded, slowing page loading times.
The easiest solution to this seems to be to replace as many inline images as I can with divs with background images. Then I can hide the div's with media query css for the mobile version.
I know there are potential downsides to this, outlined well in this post:
When to use IMG vs. CSS background-image?
So the company logo, pictures of staff, etc will stay as inline images.
Are there any issues to my approach I havn't considered? Ive read a lot about mobile optimisation, particularly with media queries, and I havn't heard of anyone doing this even though it seems quite an obvious solution where images could be inline or background.
Note, ive done some experiments with iPhones and Android (im waiting to get some Blackberrys) and I know to stop background images downloading I need to set display none to the div's parent, not the div with the background image itself.
Note2, in an ideal world sites would probably have been built as mobile first but in this situation (and often in others) there is a limit to how much the original site can be modified.
Thanks
Unfortunately, there are no great answers for the problems you’re trying to solve.
First, you have the option of moving everything from img tags to css background images. As you note, you have to be careful of losing semantic meaning by doing so.
But even if you can move to background images without losing semantic value, it is still not going to be 100% reliable. I wrote a series of tests last summer. I retested them last week in preparation for the chapter in our book on mobile first responsive web design. The tests are located at http://www.cloudfour.com/examples/mediaqueries/image-test/.
Unfortunately, Android fails every one of those techniques. You can see it downloading multiple copies of the image files via Blaze’s mobile test:
www.blaze.io/mobile/result/?testid=111031_96_316
UPDATE 3 Nov 2011: I’m currently trying to reconcile inconsistent results between what I see on Blaze and what I see using the same device in person. On my local Nexus S, it passes the fifth css test which limits the imgs by putting them inside the media queries. I watched the apache logs and confirmed the device only downloads one image instead of two for test 5. Blaze is running 2.3.3. My phone is running 2.3.6.
This is true for Android 2.2, 2.3 and 3.0. Hopefully, 4.0 will incorporate the webkit fixes that prevent this behavior:
bugs.webkit.org/show_bug.cgi?id=24223
BTW, this seems to conflict with your comment about testing setting the parent div to display:none on Android. If you’re getting different results, I’d love to hear about it.
If you keep them as img tags, what are your options? On this topic, I have written a multi-part series. The second part in the series provides an in-depth look at the different techniques:
http://www.cloudfour.com/responsive-imgs-part-2/
Again, none of the solutions are great. If you want something that is simple and will work most of the time, I’d go for adaptive-images.com. Or route images through Sencha.io SRC until we have a better solution for this problem.
BTW, sorry for having so many links that aren’t actually links. This is my first response on stackoverflow and it will only allow me to include two links.
Why not do a mobile first approach and then use media queries to enhance bigger screens.
Also you can use media queries to serve specific CSS files.
With the inline images I have tried a script block in the head and immediately after the opening body tag, which runs only for mobile devices (detect via classname added to body, or presence of a media query CSS file) that find all inline images with a certain class and empty the src attribute.
see here Prevent images from loading
<script type="text/javascript" charset="utf-8">
$(document).ready( function() { $("img").removeAttr("src"); } );
</script>
another way is to use url re-writing with mod rewrite and .htaccess or url rewrite module for iis. redirect user agent strings for mobiles to a small blank image.
see:
A way to prevent a mobile browser from downloading and displaying images
RewriteCond %{HTTP_USER_AGENT} (nokia¦symbian¦iphone¦blackberry) [NC]
RewriteCond %{REQUEST_URI} !^/images/$
RewriteRule (.*) /blank.jpg [L]
you can improve the above by loading your inline images from a different sub-domain and rewriting only those for mobile, as you don't want to rewrite all images (logo etc.)
If I'm understanding your question correctly, this seems like a perfect use case for srcset and sizes. This MDN article is a great post for learning the concept in-depth, but I will also summarize here. Here is a full, kind of complicated example:
<img srcset="elva-fairy-320w.jpg 320w,
elva-fairy-480w.jpg 480w,
elva-fairy-800w.jpg 800w"
sizes="(max-width: 320px) 280px,
(max-width: 480px) 440px,
800px"
src="elva-fairy-800w.jpg"
alt="Elva dressed as a fairy">
This code says:
If my browser doesn't support srcset use what is in src by default. Don't leave this out.
Hey browser, in srcset, here are 3 files and their natural widths separated by commas.
Hey browser, in sizes here are the widths of the space I want my image to take up depending on the media query. Use the one that matches first.
Then the browser itself will calculate which is the best image to use based on size AND screen resolution of the user then ONLY downloads that one which is pretty awesome in my book.
Ok, important thing to note is that mobile != low bandwidth != small screen and desktop != high bandwidth != large screen.
What you probably want is to make a decision based on client bandwidth and client screen size. Media queries only help with the latter.
David Calhoun has a great writeup on how to do this here: http://davidbcalhoun.com/2011/mobile-performance-manifesto
Highly recommended.
I stumbled recently on a great blog article on the subject, adressing the problem of responsive images (ie serving smaller images on smaller devices). The comments of the article are the most interesting part, and I think the replacement technique coined by Weston Ruter is a promising one :
http://jsbin.com/ugodu3/13/edit#javascript,html,live
(look at the other iterations in the comments).
It has lots of caveat (and is maybe difficult, but not impossible, to merge in an existing website, as the affect all your non absolute links, not only imgs), but I will try it (merged with a lazy loading) on my next project, which is a responsive website that my designer made quite heavy (and he does not want to make it lighter). Note that you could combine this to a php script resizing the images on demand if your server supports it.
The others common solutions for responsive imgs are cookie based (check Filament Group Responsive images plugin).
I prefer responsive images to css background because they're more correct semantically and parse-able SEO-wise. If I agree that we should not assume that bigger screen = more bandwidth, we lacks tools to address this (navigator.connection is Android only.) so assuming that most mobile users have a crappy 2G/3G connection is the safest way.
I'm not sure if you have thought about doing this but one of the things you can do is check for the width of the screen resolution with javascript and then if the resolution is less than some number (I use 480 because at that point that site looks bad) then switch the css templates from the default to the mobile themed template.
function alertSize() {
var myWidth = 0, myHeight = 0;
if( typeof( window.innerWidth ) == 'number' ) {
//Non-IE
myWidth = window.innerWidth;
myHeight = window.innerHeight;
} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
//IE 6+ in 'standards compliant mode'
myWidth = document.documentElement.clientWidth;
myHeight = document.documentElement.clientHeight;
}
if (myWidth < 48)
{
switch css template to mobile template
}
}
Adapting to an existing site sucks but we do what me must. Here is how I solved it when importing a blog's feed into a mobile site. It scales the existing image on the page to the page's width ONLY if it's larger than the screen.
var $images = $("img[width]");
$images.each(function(){
try{
var $image = $(this);
var currentWidth = Number($image.attr("width"));
if(currentWidth > screen.width){
$image.width("100%");
$image.removeAttr("height");
}
}
catch(e)
{/*alert("image scale fail\n"+e)*/}
});
By making the width 100% and removing any height attribute, the image will scale perfectly to take up the full width whether you're in landscape or portrait orientation.
Chances are, the images on your regular site are already web optimized. There's usually not that much performance boost to be gained by loading smaller images. Reducing HTTP requests will make much more of a performance boost than bringing over smaller images. It may not be the perfect solution but it is certainly going to be the least maintenance. If you can't reasonably control what images are going to be used on the site, this is a pretty reasonable solution. If nothing else, maybe this will spark another idea for you.
Are there any differences in performance or load/caching behavior when displaying images in img tags vs divs with image backgrounds?
My example:
I have a site with many overlapping images, some of which I will need to load dynamically with javascript. One issue is that I need to anchor the images to the right of the element, so that I can do a nice wipe-to-right effect. Because of this I was using a div with background image positioned right. Couldn't figure out how to do this with img but since divs are working for me I didn't know if this would matter...
AFAIK, browsers cache images the same whether they're in a DIV or an IMG. In any case, I think this one of those cases where specific performance is defined as an implementation detail internal to each rendering engine (and possibly the browsers built around them). As such, it's both out of our control as designers/developers and subject to change from browser to browser and version to version. In other words, I wouldn't spend too much time worrying about it.
The main performance difference is using background images allows you to use CSS sprites. Having one image contain a large number of images from your page means the user only has to make one request instead of one for each image.
Another difference is with responsive layouts. If you have an element that is only shown at certain screen widths (ie, not on mobile phones), it will still load the image if it is specified in the html (using display:none for instance), but most all browsers now will NOT load the image if is a background-image specified in unused media query-CSS rules. A lot of early responsive layouts got criticized because they still used the same bandwidth as the full size sites.
It is also useful with such designs because you can easily specify different images for different screen sizes. "Retina" displays on tablets and even laptops now won't look their best without 2x res graphics. So... even if you don't do such things now, it is probably a good practice to get into, because you might find yourself needing it soon!
I think by using background-image attribute in the div, the page layout gets loaded first and image present in the divs loaded later after the dom is loaded. so by using background-image the html layout is loaded faster on the web browser.
The only difference I can conceive of it this:
You can't scale images as backgrounds, although you can for img tags. This would open a scenario where background images loaded faster becuase it forces you to have the correct native size as opposed to downloading the entire image and scaling it. However, the converse could be true: given that you didn't care about image quality so much, you could deliver smaller imgs to your page and scale them up.
I'd stick with whatever rendered cleaner (and more consistently -- IE/FF/Chrome/Safari/etc).
Technical differences yes, most notably you can set the width/height of an IMG tag and it will stretch the image, which can be useful in some situations.
The main thing you've got to keep in mind though is the context of the image within the HTML document. If the image is content, say an image in a gallery, I'd use a IMG tag. If it is just part of the interface I might use a div instead.