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');
});
});
Related
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.
I am building a web application that interact with documents for later printing. In some points is similar to Google Docs. I am considering using cm/mm on the CSS of my documents pages because it will help me on the document generation. Example:
// A4 size
.page {
width: 210mm;
height: 297mm;
margin: 2cm 5cm;
}
<div class="page">
...
</div>
What are the main issues of following this approach?
W3C has a great post on the subject of CSS units. In particular:
cm: Not recommended for screen / recommended for print
The so-called absolute units (cm, mm, in, pt and pc) mean the same in CSS as everywhere else. A length expressed in any of these will appear as exactly that size (within the precision of the hardware and software). They are not recommended for use on screen, because screen sizes vary so much. A big screen may be 60cm (24in), a small, portable screen is maybe only 8cm. And you don't look at them from the same distance.
The only place where you could use pt (or cm or in) for setting a font size is in style sheets for print, if you need to be sure the printed font is exactly a certain size. But even there using the default font size is usually better.
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.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 months ago.
Improve this question
I hope this question doesn't end up being closed for being too broad a subject but I was wondering about Responsive/Adaptive Web Design, i.e. one website for all browsers, all devices.
What is the best way to implement such a site when it comes to structure and layout?
I've being trying to read up on it since mobile websites are the big thing right now and will be for a while but I can't find a list of tips and guidelines and I figured that if such a resource was available here on SO then we could all benefit.
Another thing that gets me is how is dynamic image scaling done?
Out of everything this is the thing that puzzles me most because layouts I'm guessing are probably done using percentages rather than pixel values because pixels will vary from one device to another but images are probably the key factor in achieving one website for everything.
I'm looking forward to reading people's opinions and answers, even if it is just links to tutorials on the web that I haven't found.
1. One website all browsers.
As #Tak mentioned the answers here is 'Progressive Enhancement' and 'Graceful degradation'. However the definitions he gave are not quite right. Here are the proper ones:
'Progressive enhacement' (see link) means that you code for the old browser first (IE6/7 with/without JavaScript is a good starting point) using tried-and-tested technologies such as HTML4 and CSS1, then add enhacement as you progress through testing on more modern browsers down to Chome and Safari on mobile devices which support CSS3 and most of HTML5. This way, you aim to provide any browser with the best possible combination of features supported in it (its never going to be perfect by the way so bear in mind the 80/20 rule to avoid running project into the ground).
'Graceful degradation' (see link) is kinda the same thing but backwards, its a more lazy way of doing it. You start building your site against a modern browser and then apply 'patches' and 'fixes' until its acceptable on older browsers. This ends up creating a lot more work than planning it properly from the start and what generally tends to happen with this approach is that the developer/stakeholder will give up at some point (ie. what the hell? its too much work to get this working in IE6/7 - I'll just de-scope them)
2. Best way to standardise the layout
Personally, my suggestion is that if you want a standard layout across mobile and desktop devices I suggest you use a combination of BIG fonts (so they are visible in a tiny mobile screen) and small ones (so people that have a Desktop browser can read all the detail) on a Desktop-size 900-1000px width.
This site is an example:
http://www.valuetrader.net
When I open it in my Desktop browser I see a lot of detail, but when I'm on the go and use my Smartphone all the critical information (ie should I BUY or SELL a share?) is displayed on a very big font that appears legible in my tiny screen.
UPDATE 2014
This part of the question has now effectively changed to 'Whats the best way to implement the layout?'.
At the moment (and for the last few years of widely available CSS3 support) the standard approach for cross-device layout design is to use a so called 'Responsive' layout based on media queries. There are many CSS frameworks available to get users started with mobile-friendly layouts.
The basic principle for 'Responsive' design is that scrolling on mobiles devices makes vertical space virtually endless so you are only limited by horizontal space. Thus you have to ensure that as the screen gets smaller you let the page flow to fill up all the available horizontal space, and any navigation bars or horizontal elements are folded over vertically so that items are stacked on top of each other rather than using space horizontally.
The standard way to test a site's 'responsiveness' is by dragging the side of your browser window to reduce available width.
The better way is using Developer Tools, for example Chrome has a button to toggle device mode, here is an example using Stackoverflow:
An example of a media query to specify a layout for the #site-banner element on desktop and mobile screens would be as follows:
/* DESKTOP SUPPORT */
#site-banner { width: 1000px; background: #fff; margin: 0px auto; height: 120px; }
/* TABLET SUPPORT - rules apply below 1000px width */
#media all and (max-width: 1000px) {
#site-banner { width: 700px; }
}
/* PHABLET & MOBILE SUPPORT - rules apply below 700px width */
#media all and (max-width: 700px) {
#site-banner { width: 480px; height: auto; }
}
/* MOBILE SUPPORT - rules apply below 480px width */
#media all and (max-width: 480px) {
#site-banner { width: auto; height: auto;}
}
3. How is dynamic image scaling done?
The mobile device does a lot of this for you so generally you just need an understanding of how it works. Basically, when the first mobile browsers came out they had to make sure that the sites that were already out there working for desktop browsers worked on a mobile too (otherwise nobody would use their smartphone to browse the web) so they had to come up with clever ways to detect the width of the site and resize it to the screen resolution that they had available.
For example my site 'www.desalasworks.com' is coded to 900px width, but it works fine by getting down-scaled on a small 320px screen (images on the page are automatically resampled using a variety of methods - such as nearest-neighbour sampling and bicubic interpolation, and the fonts replaced with native fonts wherever possible). As far as the image sampling goes, if you have ever pinched a photo on your smartphone to 'zoom in' and 'zoom out' you know what I'm talking about.
You generally dont need to worry about CSS to get your images to resample properly, I noticed that sometimes they are a bit funny when using percentage widths so stick to pixels if thats the case to make it easier for the browser to tell where items are in relation to one another. Note that you CAN specifically detect the mobile browser and set the width of your site to 320px and everything in it to fall in-line accordingly but in reality this is not necessary to have a working site on a mobile device and doing this will force you to maintain 2 sites, a mobile site and a desktop site (which some companies are happy to do).
4. Percentages / fixed width.
Personally I tend to use fixed width centered on a screen (using CSS margin: 0px auto), I haven't used percentage widths for a LONG time, mostly because its a bit of a nightmare to standardise the layout. If you do use percentage widths you'll basically have to do a lot more testing so I would tend to veer away from them.
Bear in mind this is just my opinion, some 'reponsive web' gurus will swear by percentage widths on just about everything, I'm just not sold on the idea of sacrificing predictability of the layout for what I see as marginal benefit. But then I come from a background of building desktop webapps, I'd probably think differently if I was just focused on mobile web (where horizontal space is at a premium and layouts tend to be simpler).
You're correct about the percentages.
As art elements, the habit is to (with CSS) set a percentage width on an image and set it's display to block.
There's a couple techniques for changing the resolution of images based on the client's screen size as well, like responsive-images.js. I don't think there's a perfect answer on how to tackle this issue yet.
If you're really interested in responsive design, I highly recommend Ethan Macotte's Responsive Web Design.
The two buzzwords at the moment are graceful degradation and progressive enhancement and I'm a fanboy of the latter. Graceful degradation means you hide and/or resize elements on the page for viewing on a mobile screen. Progressive enhancement means you code for the mobile browser, then add bits on if they're using something bigger. The latter is best because it prevents mobile browsers having to download giant images and a bunch of includes it'll never use, and mobile bandwidth is at a premium.
I use 320andup which is a great way to style a web page at 320px for mobile browsers, then other resolutions for tablets, netbooks, PCs and ridiculously large Mac displays. Web pages look great on all resolutions.
I never use percentages. I style a web page at 320px fixed width, 480px fixed width, etc so I know exactly how it'll look on each device. I do all my image scaling on the server with variables in the URL - the server caches the resized images for later page loads. That way my shiny web 2.0 logos are tiny for mobile devices but large on the big screen. This is another reason not to use percentages!
The answer by Steven de Salas is excellent! If you have the time, effort, and/or team available to do a hand-crafted mobile website, then go for it with his tips.
But if you want just an automated, mobile-ifying function, then that's also possible. In fact, starting with an automated function that can make a website mobile-friendly is a good starting position for making your own customized version.
Basic Approach
Use document.styleSheets[0].cssRules to parse the CSS Rules and cssRule.style to change previously configured styles. The advantage here is clear: Most of your CSS already done can automatically be ported over to the mobile version.
Basic Solution
viewport — Set your viewpoint in the header: <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=0">
img.width — The simple part is to parse every image and adjust the width according to a scale (currently, I use 1:2 ratio for image sizes).
document.styleSheets[0].cssRules[i].style — Use document.styleSheets[0].cssRules and the rule.style attribute to parse the CSS file for your site, and adjust everything up/down in size as needed.
Demo
var isMobile = false;
var ui_scale = 1;
var image_scale = 1;
document.getElementById('mobile-ify').addEventListener('click', function(ev) {
isMobile = !isMobile;
if(isMobile) {
ui_scale = 2;
image_scale = 2;
} else {
ui_scale = 0.5;
image_scale = 0.5;
}
const styles = getUIScaleableStyles();
const stylesheet = document.styleSheets[0];
const ruleList = stylesheet.cssRules;
for (var i = 0; i < ruleList.length; i++) {
const rule = ruleList[i];
for (const style of styles) {
if(rule.style[style]) {
const fontsize = rule.style[style];
const numeric = parseInt(fontsize, 10);
const unit = fontsize.replace(/^\d+/, '');
if(unit !== '%') {
const resize = ui_scale * numeric;
const newvalue = resize + unit;
rule.style[style] = newvalue;
}
}
}
}
const images = document.getElementsByTagName('img');
for (const image of images) {
const oldwidth = image.width;
const newwidth = image_scale * oldwidth;
image.setAttribute('width', newwidth);
}
});
function getUIScaleableStyles() {
const updateableStyles = [
'fontSize',
];
return updateableStyles;
}
.text {
font-size:1em;
}
<center>
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/f4/Honeycrisp.jpg/1920px-Honeycrisp.jpg" width="100">
<br><br>
<button id="mobile-ify"><span class="text">Mobilify Site</span></button>
</center>
I have a webview that displays an image, as shown in the code below. The bundle also has a DGT64#2x.png with dimensions of 128x128 for use on the iPhone4. The DGT64#2x.png never shows. Is there a way to display either/or depending on whether it's an iPhone or an iPhone4?
<img src="DGT64.png" width="64" height="64" align="left" style="padding:2px;"/>
The way to do it is with CSS backgrounds. Just embedd all your 2x stuff in a subsection in CSS. The key is also to set the -webkit-background-size. Here is an example of the portion of the css (both retina and not) for a div with the id Ampersand that acts as an image.
div#Ampersand {
background: url('AmpersandBurned.png');
width:43px;
height:97px;
float:left;
-webkit-background-size: 43px 97px;
}
#media screen and (-webkit-device-pixel-ratio: 2) {
div#Ampersand {
background: url('AmpersandBurned#2x.png');
width:43px;
height:97px;
float:left;
}
}
I don't think the #2x trick works with web content. Sounds really useful though, I would certainly file a bug with Apple to request that.
If you are generating the above HTML from your app then I think the best way for now will be to detect if you are running on a Retina display device and then adjusting the image name manually.
You can detect the Retina display by doing something like this:
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)]) {
if ([[UIScreen mainScreen] scale] == 2) {
// Use high resolution images
}
}
(Took that code from an answer I found here in SO)
Currently the best way to do this is by referencing your images in your CSS file using the background-image property. Then, you can use a special CSS file that is only loaded by devices with high resolution screens to override these properties.
See this blog post for more information.