Pure CSS Retina Image Replacement

On the latest website I've been working on I decided to introduce myself to x2 images for retina displays. A retina screen is simply a ultra high definition display such as that found on the iPhone or iPad. Standard 72 DPI images don't look crisp on these extra dense screens.

The solution is to use images that are twice the pixel size to take advantage of the extra definition. Obviously downloading larger images will take longer so ideally we want to only load these images on devices that will actually benefit from them.

I researched several of the common approaches used to load retina images. Many use JavaScript but I personally prefer a CSS only method even if that means extra HTML markup so I have developed my own solution.

Replacing CSS background images is easy using media queries:

@media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) {
  #slider {
    background-image:url('../images/slider-bgx2.jpg');
    background-size:100% 100%;
}

Where it gets tricky is CSS cannot change the source path of HTML image elements, or at least I'm not yet to a see a reliable method. My alternative uses some extra markup to allow us to overlay the retina image on top of the standard HTML image:

HTML:

<div class="retina" style="width:100; height:100px;">
  <img src="normal-image.jpg" alt="Responsive Retina Image" width="100" height="100" />
  <span class="overlay" style="background-image:url('normal-imagex2.jpg');"></span>
</div>

CSS:

/* Image replacement */
.retina {
  position:relative;
  display:block;
  img {display:block;}
}
.retina.inline {display:inline-block;}

.retina .overlay {
  display:none; /* Hidden by default */
  position:absolute;
  left:0;
  top:0;
  width:100%;
  height:100%;
  background-size:100% 100%;
}

@media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) {
  .retina .overlay {display:block}; /* Display retina on top */
}

Basically what this does is wrap the HTML image in a container that either shrink wraps (e.g. float) to the size of the image, or has its size set to match the image. Inside the container and after the image element we add an empty span element that is set to take the size of the container and in effect it layers itself above the HTML image to display the retina image. This overlay is only shown on retina devices.

I have tested this solution in Firefox, Firebug says that the x2 retina images are not loaded on standard 72 DPI screens. The only downside is the extra markup and retina displays will load both the x2 and standard size. I haven't checked this method on 'display:inline' images but '.retina.inline {display:inline-block;}' should work in my opinion.

If you have any questions or trouble using my method let me know in the comments below.

Comments

  • safnbmxzvmbn

    01 Oct 2013 13:17:06

    > Where it gets tricky is CSS cannot change the source path of HTML image elements, or at least I’m not yet to a see a reliable method. My alternative uses some extra markup to allow us to overlay the retina image on top of the standard HTML image:

    > <div class=“retina” style=“width:100; height:100px;”>
    > <img src=“normal-image.jpg” alt=“Responsive Retina Image” width=“100” height=“100” />
    > <span class=“overlay” style=“background-image:url(‘normal-imagex2.jpg’);”></span>
    > </div>

    why not just place in your html two img tags and manage their visibility from css? Like

    ———————————————————
    <p><img src=“1x.jpg” style=“float: left;” class=“t-retina-normal”> <img src=“1x.jpg” style=“float: left;” class=“t-retina-2x”> Lorem ipsum dolor sit amet…</p>
    ———————————————————

    and something like this in css?

    ———————————————————

    /* toggle retina images */

    .t-retina-normal {display: inline-block;}
    .t-retina-2x {display: none;}
    @media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) { .t-retina-normal {display: none;} .t-retina-2x {display: inline-block;}
    }

  • Luke Franklin

    08 Jan 2014 18:12:01

    Sorry safnbmxzvmbn,

    I missed your comment because it was filtered to spam… something to do with your nickname and email address looking like gibberish I guess.

    Anyway, in regards to your comment:
    That is one option, however in your example I think browsers may download both versions of the images even when not displaying the retina version.

    Cheers,

Leave a comment