Image icons in HTML that display nicely in Retina displays - html

I want to have nice images in my HTML that display very nicely on browsers in computers with Retina displays. I'm guessing I just have to have a high resolution image in my img tag. But then the lower resolution browsers will all have to download this bigger file and then downscale it, maybe resulting in a lower quality image than if I downscaled it in a tool like photoshop.
I'm hoping there's something like this I can do:
<img src="/example.png" src-retina="/example-high-res.png"/>
What's the proper way to display 2 different images, 1 for normal displays and 1 for retina displays?

With CSS it's easy
With an image source attribute, there is less of standard way to do it. I've used a JS based approach myself checking window.devicePixelRatio:
<img id="example-img" width="100" height="100"/>
<script>
if (window.devicePixelRatio > 1) {
$('#example-img').src = "/example-high-res.png";
} else {
$('#example-img').src = "/example.png";
}
</script>
But if you can, use CSS and media queries. It's far cleaner.

There are several different approaches out there, and they have upsides and downsides. Apple themselves actually serve both retina and standard images to retina devices, which works but obviously results in pretty heavy downloads.
If you want something that's semi-automated, try Retina.js. From the description:
When your users load a page, retina.js checks each image on the page
to see if there is a high-resolution version of that image on your
server. If a high-resolution variant exists, the script will swap in
that image in-place.
The script assumes you use Apple's prescribed high-resolution modifier
(#2x) to denote high-resolution image variants on your server.

You need to make two (or possibly more) CSS files and use them depending on the user's browser settings with the help of JS. The css file for mobile site should make a new layout that is fully visible in a mobile phone.
Check out this SO Question to make a better understanding of the topic.

Use the responsive design principles for scaling up or down the image size depending on the device screen resolution.
In CSS you may define the max-width and max-height of the target device. This is how you declare it in CSS:
#media only and (max-device-width:1024px) and (orientation:portrait)
After that you have to specify the element width and height in percentage, relative to the parent element. This is the working method, however not the best one in terms of bandwidth consumption on mobile devices, because even if we set the percentage lower, the image is uploaded in it's native size and the downscale is done after the browser parsed the CSS document.
There are some proposals from W3C on terms how should the image been handled by different devices, but none of them are commonly accepted and standardized.
One of the most well received proposal is the new <image> and <source> tags, which accept different image source and depending the screen resolution use the most opportune image dimension.
<picture alt="">
<!-- low-res, default -->
<source src="small.jpg">
<!-- med-res -->
<source src="medium.jpg" media="(min-width: 400px)">
<!-- high-res -->
<source src="large.jpg" media="(min-width: 800px)">
<!-- Fallback content -->
<img src="small.jpg" alt="description of image">
</picture>
There is a polyfill which mimic the proposed picture element: https://github.com/scottjehl/picturefill
Here are two thoroughly explained article about the concept:
http://nicolasgallagher.com/responsive-images-using-css3/
http://css-tricks.com/on-responsive-images/

You could use a div with css background definition that specifies the image. Using css media-queries you could pick the right css definition when the client is a Apple device with a 'retina-display'.

You can do it with jQuery:
HTML:
<img src="/example.png" src-retina="/example-high-res.png"/>
Javascript:
if (window.devicePixelRatio > 1) {
$('img').each(function() {
var src_retina = $(this).attr("src-retina");
$(this).attr("src", src_retina);
});
}
This demo shows the way it works: http://jsfiddle.net/TLz7S/.
Note: I may be detecting the retina display wrong; I don't actually have one. If someone finds that incorrect, please let me know.

Related

html picture element not honoring small media query

I've got a thing like this:
<picture>
<source media="(min-width:1200)" srcset="big.jpg">
<source media="(min-width:840)" srcset="small.jpg">
<img srcset="big.jpg" alt="Test" />
</picture>
I'm also using picturefill.
My issue is that both firefox and chrome (the 2 I'm currently testing on), will load only big.jpg, even in small screens. Checked also on console's network trace.
My css sets img as basic fluid:
img{
display: block;
max-width: 100%;
height:auto;
}
So what's wrong in my code?
As for I haz kode's comment, the answer is: my code lacked unit declaration in media queries.
As for completeness, I also write here a better code for my use case: having a default image for small screens and different one from 840px up.
<picture>
<source media="(min-width:840px)" srcset="big.jpg">
<img srcset="small.jpg" alt="Foradori">
</picture>
This will work correctly and download only the right image for the current breakpoint.
Also remember we need picturefill to ensure crossbrowser support.

Changing image via media queries

I want to change a image when the display is smaller than 400px (for this purpose i cant use the image as background). I thought displaying 1 with display:block and to hide the other with display: none.
My question is if i do it this way, will the browser load both images and hide one of them or will it only load one of them? (display:block).
If the browser load both images i need to find a way to change the src of the image
to avoid loading the image twice (not using normal css mediaqueries) you could use window.matchMedia (JS);
var breakpoint = window.matchMedia( "(min-width: 400px)" )
if (breakpoint.matches) {
// window width is at least 400px
// you load one img
}
else {
// window width is less than 400px
// you load other img
}
ok .. you could check this stackoverflow post, Media queries and background images you must use min-width and mix-width into css and there is a webpage with more information for mediaquery´s assets http://timkadlec.com/2012/04/media-query-asset-downloading-results/
You could also use responsive images for that - new <picture> tag or srcset attribute for classic <img>. It is nicely explained here:
http://responsiveimages.org/
It is still quite new technique and it'ss not supported by all browsers yet (srcset, picture), however there are polyfills (i.e. Picturefill) that simulate it by JavaScript.

Browser is loading two images - one for srcset, one for src (Chrome 41 et al)

I'm using the srcset attribute on a web page I'm developing.
<img src="img/picture-820x496.jpg"
srcset="img/picture-820x496.jpg 1200w,
img/picture-374x226.jpg 992w,
img/picture-305x185.jpg 768w,
img/picture-707x428.jpg 300w" />
If I check which resources get loaded with the page, I see that Chrome 41 as well as FF using the polyfill as well as Safari 7 always load the image twice - once the full resolution and once the according size from the srcset attribute. What am I doing wrong here?
I had a similar problem, I found that if the src image was not one of those available in the srcset images the browser would load the src image regardless. The solution was to ensure the src image url matched one of the srcset images urls.
As an aside - as I understand the spec the w value following the image url should match (roughly) the width of the image. This allows the browser to best determine the image to display based on the sizes attribute and device pixel density. So you should probably alter the w values in your markup and add the sizes attribute (which allows you let the browser know the rendered image size using media queries and a fallback ie. (min-width: 640px) 600px, 50vw). Consider the example below:
<img src="img/picture-820x496.jpg"
srcset="img/picture-820x496.jpg 820w,
img/picture-707x428.jpg 707w,
img/picture-374x226.jpg 374w,
img/picture-305x185.jpg 305w"
sizes="100vw">

media queries / loading different image depending on screen size

This might be basic but I'm getting lost in all the solutions I've managed to find on the web.
I have a running website (www.webstalab.com) based on Twitter Bootstrap 3 but the image used (depicting two statues holding a ball) is quite big in size (around 900kb) therefore loads way too long on slower internet connections.
The present photo is 1920 pixels wide, is responsive and it is not a background image. (I couldn't achieve the desired layout with the background image approach).
All I want to do is create 3 different size versions of the same photo (one around 800px wide, one around 1200px wide and keep the original at 1920px wide) and get the browser load the appropriate version of the image depending on what screen size and resolution is used to view the website. I also plan to cut the size of the original (1920 pixels wide) photo a bit so it loads a bit faster.
I suppose CSS3 media queries is the way to go with this?
Will media queries also solve the retina display issue?
Can anyone suggest a good article covering the basics?
I'd prefer a solution without javascript (just in case the user has it switched off).
The website is online so you can check the source code.
Thanx all!
If you use the img tag for showing the image, then yes, you will need a JS solution.
So if you want to use media queries, you will need to use the images as a background on for example a div tag:
Example with background-image on a div
The example is without retina display handling, but here is an article on handling that:
Retina Display Media Queries
As long as cookies are sent with all image requests, you can redirect to low res images using rewrite rules in .htaccess file depending on the value of a cookie set at the very beginning of the page load using JavaScript.
index.html:
<head>
(...)
<script type="text/javascript">
document.cookie = "res=" + (screen.width <= 700 ? "low" : "high");
</script>
<!--styles-->
(...)
<head>
.htaccess in /images folder:
RewriteEngine on
#if cookie res=low exist, redirect to low/ folder
RewriteCond %{HTTP_COOKIE} res=low
RewriteRule ^(.+)$ low/$1
#if low/ image does not exist, use default (hi res)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^low/(.+)$ $1 [END]
I don't know about possible performance hit. Just trying it right now.
Note this doesn't help with load speed, see comments.
Bootstrap 3 has some responsive utilities which allow you show/hide elements via media queries.
http://getbootstrap.com/css/#responsive-utilities
e.g. Give an element the class visible-xs and it will only show on XS sized devices.
I've just implemented this in my view, rather than in CSS, as I wanted to use a straight img not a "div with background image"
<div class="navbar-header">
<a href="/home" class="navbar-left" >
<img class="logo visible-sm visible-md visible-lg"
src="/images/logos/logo-trans-96-wht-250x70.png"
width="250" height="70"
alt="Home"/>
<img class="logo visible-xs"
src="/images/logos/logo-trans-96-wht-200x56.png"
width="200" height="56"
alt="Home"/>
</a>
</div>
It doesn't feel very elegant from a CSS point of view, but this is one of the few times you can't control something from CSS.
It gives you a potentially powerful yet simple technique for responsively swapping entire HTML structures.

Automatic Retina images for web sites

With the new Apple MacBook Pro with retina display, if you provide a "standard" image on your website, it'll be a little fuzzy. So you have to provide a retina image.
Is there a way to automatically switch to #2x images, like iOS (with Objective-C) does? What I've found is: CSS for high-resolution images on mobile and retina displays, but I wish I could find an automatic process for all my images, without CSS or JavaScript.
Is it possible?
UPDATE
I would emphasize this interesting article suggested by #Paul D. Waite and an interesting discussion about it linked by Sebastian.
There is a new attribute for the img tag that allows you to add a retina src attribute, namely srcset. No javascript or CSS needed, no double loading of images.
<img src="low-res.jpg" srcset="high-res.jpg 2x">
Browser Support: http://caniuse.com/#search=srcset
Other Resources:
WebKit release post
W3C documentation for srcset
good explanation about why and how to use srcset
Chris Coyer's post for more good info
There are different solutions, each with its own pros and cons. Which one is best for you depends on various factors, such as how your website is designed, what kind of technology your typical visitors are using etc. Note that retina displays are not limited to the Macbook Pro Retina and the coming iMacs, but also include mobile devices, which may have their own needs.
The problem is also closely related to images in responsive designs in general. In fact, it is probably best to utilize generic responsive design techniques, instead of designing for specific devices. After all, technology will keep changing all the time in the future, too.
Some of the solutions/discussions I noted:
Vectors wherever possible including CSS techniques (gradients, rounded corners etc.), SVG and icon fonts.
Serving high resolution ("retina") images, but compress them more (JPEG quality), as suggested by Yoav Weiss, or let the mobile networks compress them when really needed (i.e. when mobile), as suggested by Paul Boag.
Adaptive Images, a (mostly) server side solution. It is based on a cookie storing the screen resolution, a web server configured to serve images from a PHP script, and named script to read the cookie and serve the appropriate image.
A bunch of possibilities well described and discussed on Smashing Magazine.
Serving just slightly higher resolutions to smooth retina portrayal a little, as suggested in a video by Paul Boag.
The #1.5x technique on A List Apart is basically the same idea.
In the near future, the <picture> tag may become a solution supported by a W3C working group and even Apple.
A JavaScript technique proposed by Jake Archebald.
An extensive discussion of different techniques on Smashing Magazine and the problem in general.
As the other answers show, there are even more techniques - but probably no best practice, yet.
One thing I wonder is how to test and debug some of these techniques, without having the respective device(s) available...
Since no one's mentioned the obvious yet, I'll float it out there: where possible, just use SVG. They appear at beautiful retina resolutions with no effort whatsoever.
Support for it is good with IE8 being the main dinosaur to worry about. Gzipped file sizes are often better than bitmapped (png/jpg) formats and the images are more flexible; you can reuse them at different resolutions and restyle them if necessary, which saves both development time and download bandwidth.
Here is the less mixin I use to achieve this for background images. retina.js doesn't work for background images if you are using dotLess, since it requires its own mixin which itself uses script evaluation which isn't supported in dotLess.
The trick with all of this is to get IE8 support. It can't easily do background-size so the base case (non mobile media query) has to be a simple, non-scaled icon. The media query then handles the case of retina and is free to use the background-size class since retina will never be used on IE8.
.retina-background-image( #path, #filename,#extension, #size )
{
.background-size( cover );
background-image: url( "#{path}#{filename}#{extension}" );
#media only screen and ( -webkit-min-device-pixel-ratio: 2 ),
only screen and ( -moz-min-device-pixel-ratio: 2 ),
only screen and ( -o-min-device-pixel-ratio: 2/1 ),
only screen and ( min-device-pixel-ratio: 2 )
{
background-image:url( "#{path}#{filename}#x2#{extension}" );
background-size:#size #size;
}
}
Usage sample:
.retina-background-image( "../references/Images/", "start_grey-97_12", ".png", 12px );
Ths requires you to have two files:
start_grey-97_12.png
start_grey-97_12#2x.png
Where the 2x file is double resolution for retina.
Just provide retina images to everyone, and squeeze the image to half its native size inside the image element. Like let's say your image is 400px wide and tall - just specify the image width as 200px to make it look sharp like this:
<img src="img.jpg" width="200px" height="200px" />
If your image is photographic, you can probably increase the JPG compression on it without making it look worse, because the JPG compression artifacts probably won't be visible when the image is displayed at 2x: see http://blog.netvlies.nl/design-interactie/retina-revolution/
if its background images a simple way to do this is:
#image { background: url(image.png); }
#media only screen and (-webkit-min-device-pixel-ratio: 2),
only screen and (-moz-min-device-pixel-ratio: 2),
only screen and (-o-min-device-pixel-ratio: 2/1),
only screen and (min-device-pixel-ratio: 2) {
#image { background: url(image#2x.png); background-size: 50%; }
}
another simple way is to use this method:
Just replace:
<img src="image.jpg" alt="" width="200" height="100" />
with
<img src="image#2x.jpg" alt="" width="200" height="100" />
I've found this interesting way for providing multiple resolution images.
It actually uses CSS, something I wanted to avoid, and works in Safari and Chrome only.
I'm talking about image-set.
Here's an example, provided by Apple (here):
header {
background: -webkit-image-set( url(images/header.jpg) 1x,
url(images/header_2x.jpg) 2x);
height: 150px; /* height in CSS pixels */
width: 800px; /* width in CSS pixels */
}
I wanna share also these two links:
Safari 6 and Chrome 21 add image-set to support retina images
The image-set() notation #W3C
With JSF you could create a custom Facelets tag to save the fuzz of having to add srcset to each image.
In your taglib.xml you could have something like:
<tag>
<tag-name>img</tag-name>
<source>tags/img.xhtml</source>
<attribute>
<name>src2x</name>
<required>true</required>
<type>java.lang.String</type>
</attribute>
</tag>
And your tag could look something like:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:fn="http://xmlns.jcp.org/jsp/jstl/functions"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<img src="#{fn:replace(src2x, '#2x', '')}"
srcset="#{src2x} 2x"/>
</ui:composition>
Which could be used like:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:myTag="http://your.com/namespace-of-taglib">
<myTag:src2x="image#2x.jpg"/>
</html>
And will render:
<img src="image.jpg"
srcset="image#2x.jpg 2x"/>
This problem is especially tricky with responsive sites where and image can be of varying width dependant on browser size. Also when dealing with a CMS where multiple editors are potentially uploading 1000s of images it to me seemed unrealistic for me to ask people to upload specially compressed images.
So I wrote a script that takes this into account, it fires at the bottom of the page and on resize finish. Each time taking into account pixel density and the size the image is occupying.
http://caracaldigital.com/retina-handling-code/
If you are not frustrated by fear of using java-script then here is a good article http://www.highrobotics.com/articles/web/ready-for-retina.aspx. It has very simple solution.
And the example in JSFiddle is worth a thousand words.
Using:
<img onload="getImgSrc(this,'image_x1.png')" width="100" height="100" />
JS:
/* RETINA READY IMG SRC */
function getImgSrc(img, src) {
var srcResult = src;
// if high-res screen then change _x1 on _x2
if (window.devicePixelRatio > 1 &&
src.indexOf("_x1.")>=0) {
srcResult = src.replace("_x1.", "_x2.");
}
img.onload = null; //protect from second rasing
img.src = srcResult;
}
$(document).ready(function(){
// fire onload trigger on IMG tags that have empty SRC attribute
var images = $('img:not([src=""])');
images.each(function(i) {
$(this).trigger('onload');
});
});