Skip to content

Instantly share code, notes, and snippets.

@steckel
Created March 2, 2012 19:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save steckel/1960893 to your computer and use it in GitHub Desktop.
Save steckel/1960893 to your computer and use it in GitHub Desktop.
Hi-Res Web

Hi-res web

What the hell is going on here?

This is already happening. We have devices in the market that already have high pixel density displays besides Apple's Retina screens and we know no one plans on scaling back on this technology. We also know that, all though, the majority of these devices are on mobile phones and tablets, mobile is playing a larger part in the web and also isn't going to start slowing down any time soon.

Will we all just blindly follow Apple's iOS workflow and create multiple assets for multiple resolution targets? some-image.png and some-image@2x.png?

There's definitely more options than this and the web isn't such a simple place where we can just accept apple's native app work flow and expect it to work without any consequences.

We'll need to worry about a few things:

  • Backwards Compatibility
  • Network Connection/Bandwidth
  • Semantics
  • Workflow/Overhead
  • Asset Consistency

and I'm sure a bunch more I haven't thought of yet.

What are we currently doing?

In the current state of the web we've been equipped with CSS3 media queries to handle hi-res imagery and responsive layout and, from my experience, it's been working great. However, I'm beginning to hit a brick wall.

(An example media query: only screen and (-webkit-min-device-pixel-ratio: 2))

While pulling in different stylesheets or switching background images depending on a media queries has been good, it hasn't solved the problem for assets that aren't handled by CSS ( tags primarily). There also isn't any way to determine what assets to serve up depending on your network connection; Just because a user has an amazing mobile phone, if their connection speed is sub optimal, we probably shouldn't force them to wait 5 minutes for hi-res iconography.

Sass, Less, etc.

For those using dynamic style sheets such as Sass or Less, creating a mixin to handle this repetitive CSS workflow has probably been your savior (I know it has been mine).

Example:

@mixin background-image-retina($file, $type, $width, $height) {
  background-image: url($file + '.' + $type);

  @media (-webkit-min-device-pixel-ratio: 2) {
    & {
      background-image: url($file + '@2x.' + $type);
      -webkit-background-size: $width $height;
    }
  }
}

// Example
#foo {
  @include background-image-retina('foobar', 'png', 10px, 20px);
  background: repeat;
}

However, in my humble opinion, this gives too much power to boilerplate code or configuration and I prefer a simple convention more people can enjoy without having to barrow, author, or learn a new stylesheet technology if they don't have the opportunity or desire to (even though I'd still encourage them to).

Also, what about sprite maps? Is this truly compatible with your current method of sprite map generation? I've been able to find a workflow to make it semi non-painful but, it's not ideal.

Image Markup

Image tags are not so "dynamic" but, we do have the option at setting their width with a percentage and omitting their height. This is nothing new, and in fact, I've been doing this since I was in the 4th grade playing on geocities. However, it puts a bad taste in my mouth when I have to barrow from that experience for use in my "professional" career.

If we set an image's width to 100% and allow their parent element to define their pixel width, we create the opportunity for flexible image sizes. There are two sides to this coin however, with a large image asset and forcing a smaller pixel width than it's source is set to, we don't see any artifacts from the resize but, once we go upward it can get ugly fast.

<div style="width:320px;">
  <img src="this-image-is-higher-res-than-it-needs-to-be.png" width="100%" alt="a pony" />
</div>

So what does this mean? It means that on a device like an iPhone 4 with a Retina screen, we need to provide an image two times the screen's width that we're used to designing for. 320px wide portrait layout means we need a 640px wide asset -but wait, what about landscape support? While being held landscape the layout's is at 480px width, so we need a 960px width asset... you see where this is going don't you?

For a mobile site, optimized with the popular iPhone 4, we'll need a 960px wide asset to some how magically load over your (crappy) 3g connection.

Let's take a step back here for a moment, but, what if we're on wifi? What if we're not even on an iPhone 4 and we're a year or two in the future with an iPad with a Retina display or some new laptop or desktop screen with a hi-res display. Since we're using a kick ass broadband connection, do we still have an issue? Unfortunately yes.

Unless we want to start forcing people to wait for a progress bar to load up all of our assets (a viable solution) before loading any hi-res web site, we're going to run into the problem where our hi-res displays have out-ran our bandwidth.

Dead end. We're fucked. What else can we do?

Maybe SVG?

Okay, so let's say you come to the same conclusion as I did. I'm going to support hi-res assets for iconography and other important elements I'd usually find in my stylesheets since, it's not only easy to implement, but will be expected to be crisp and clean when compared to photos. Maybe I can even utilize SVG assets for some of these UI elements.

At this point, you can decide for yourself if your target browsers support SVG and if it's a good solution when compared to using media queries. If you decide to go that route, you may end up in JavaScript using something like Raphael.js.

However, we still don't have hi-res support for our photos or any other similar content we usually find in tags. Luckily, now that we're in JavaScript though, we have a few more options.

JavaScript

Whenever I start solving my web problems with JavaScript I feel like Leonardo Dicaprio in Inception, "I can control EVERYTHING... -OH SHIT! I'm going to die!""

JavaScript is usually my silver bullet and I feel pretty guilty about that. Solving markup, semantics, or style problem with JavaScript is pretty easy but, you'll begin to fall into a rabbit hole and realize that you've simply "done it wrong." You didn't begin this project writing a JavaScript application, this is a web site. The JavaScript is only meant to augment and enhance it -not dictate it.

With that said, what would be good ideas for JavaScript to help us do when it comes to a hi-res web.

  • Front load assets (progress bar/loading screen)
  • Detect hi-res displays outside of stylesheets
  • Determine network connectivity
  • Augment and enhance the markup

Great! These offer us a ton of tools to help us do this.

Let's say that our site is a little on the heavy side since we're offering hi-res iconography and decorative imagery in the stylesheets. We decide that our design allows for us to make a pretty pre-loader and no one thinks it's tacky (meh).

Maybe we're smart enough to write some JavaScript and record how long it took to preload those assets. Maybe even better, we have access to a navigator.connection variable that tells us if we're on 3g or wifi. Now we have a guess of how good or bad their connection speed is and we can use this information to decide on if we want to server up hi-res assets

Now, write some JavaScript to detect hi-res displays.

if(window.devicePixelRatio >= 2) {
  alert("ZOMGUHAZHIREZ")
}

Saweet! We have a hi-res display and our connection isn't complete shit so we start using jQuery to search for all tags with a class of .retina and append the string @2x to their "src" in order to start switching their assets. Maybe we're even smart enough to preload those new assets before we make the switch.

Right on! We have a hi-res we -wait a minute. This is a lot of crappy work! I already said I'm not a fan of tons of boilerplate code and configuration and we just hit the mother load.

HALP: We need something better

Even when we do everything right, it still isn't very fun.

We didn't even mention all the hard work on the asset production side of things that would be requires to get us a image-asset.png and an image-asset@2x.png and/or prepare a-huge-sprite-map.png and-one-for-retina.png that won't require tons of stylesheet work.

So, what do we want? Do we want more HTML markup to help with this problem? Do we need better image formats? Does there need to be additional browser technology that helps us with this?

I want a simple convention for everyone to be able to utilize with ease.

A new image format?

Maybe we just need a new image format that would be able to contain different target resolutions. That's sort of how .ico works right?

This way, the web developers wouldn't have to worry about how to implement this hi-res asset because we'd assume as long as the designers put the right resolutions inside the responsive image format, it'll magically show up in the browser.

I love it. We're done -wait...

  • Who's going to make this happen?
  • Will it be available to use within PhotoShop?
  • How quickly will browsers support it?
  • Does this effect download speeds?

While this is a great sounding solution, it's pretty flawed until we have more information or more people helping to define the approach. Out of all four of my stated concerns for it, which is my biggest fear? Number Four: **Does this effect download speeds?

If we create a single asset that contains multiple screen resolution targets (not vector... that's a different story) wouldn't we be increasing the file size? Would the web server be able to select which "slice" of the image to send down the pipe? How would it know what we want?

Damn it, I can't figure out a way to make this work with my limited knowledge of image formats.

Do you have any suggestions?

Markup

Maybe the fix is markup. Maybe we can make the image tag more like the video tag with media queries to decide between sources?

<img src="default.png" width="600px" height="400px" alt="A Cat">
  <source src="lo-res.png" media="only screen and (-webkit-min-device-pixel-ratio: 1)"/>
  <source src="hi-res.png" media="only screen and (-webkit-min-device-pixel-ratio: 2)"/>
</img>

This would be great for backwards compatibility but, it wouldn't be the most semantic solution if we had to reference -webkit-min-device-pixel-ratio. That's a visual reference and I can get a little semantic-nazi about those types of things.

Also, what happens when mozilla get's in the game. Do we need to have extra markup for sources specifically for -moz-min-device-pixel-ratio or -ms-min-device-pixel-ratio? Clearly there needs to be a standard enforced on all of these vendors for this media query even if we don't include it in markup in the future.

While I like the idea of additional source tags, I don't feel that the idea is complete.

Any ideas on how to make this work?

Any other ideas?

Stylsheets/CSS

I feel we have the tools we need to get this done pretty well in our stylsheets with CSS and tools like Sass or Less. While improvement on this would be welcomed, I definitely don't think it would be able to solve the problems we identified earlier. With that said however, I'd love to hear any suggestions.

JavaScript

At this point, I just don't believe that JavaScript is the answer (and I feel guilty saying that).

JavaScript is how I'll solve this problem for now, and improvements upon my process are welcomed but, I also don't believe that it's the proper environment to own the responsibility of managing hi-res images and assets.

Maybe it's a compromise however, and someone will make a framework that makes communication between these technologies easy to manage from a JavaScript API.

@OscarGodson
Copy link

Another major missing factor is a JS API to get the speed of your internet connection. Who cares if you have a high-res device if you're on 3G? I just wanna see the page. So you could do something like

//If the connection speed in >5MB
if(window.connection.speed > 5120 && window.devicePxRatio >= 2){
  //show high res
}
else if(window.connection.speed <= 5120 && window.devicePxRatio >= 2){
  //If we're on a slow connection, but you support high res, wait until high-res is done loading, then replace it with the low res one.
  $(high_res_version).appendTo('#hidden_loader_area').load(function(){
    $(low_res_one_on_page).replaceWith(high_res_version);
  });
}
else{
  //show low res
}

Without it i think that serving up high-res to any device or computer on slow connections is the wrong way to go.

I also don't want to overcomplicate the already complicated DOM with a bunch of img sources. I'd rather see media attributes with the ability to add a source on a single <img> tag considering it is the same image just a higher res version. Sort of like what you have:

<img src="lo-res.png" media="only screen and (-webkit-min-device-pixel-ratio: 2) then (src=high-res.png)"/>

@steckel
Copy link
Author

steckel commented Mar 2, 2012

I totally agree with the "shitty connection" -> "show them the damn page."

I'm curious if there needs to be a more universal implementation of that concept for everyone to revolve around and remix until we have a convention everyone can adhere to. This is especially going to remain important in the mobile device world which is only getting larger.

I also like your approach of updating the img tag without adding source elements. It looks a bit more clean when it's a simple hi-res or default-res option.

What do you think of even more flexibility with tags and media queries? Media Queries can create context like screen resolution in respect to dimensions and maybe used to request specific crops of an image when working with dynamic content servers like Adobe's Scene7. While this wouldn't necessarily support hi-res web it would contribute in a more responsive one for sure.

@jeremyruppel
Copy link

Nice writeup! I feel like there may be a good solution waiting to be built right now using media queries and less.js. Using dynamic stylesheets that can adapt to the client environment might be a very clean way to approach this. Also, media queries can also detect orientation, so that could be baked in to the solution as well.

As far as preparing assets though, that's going to be a bitch. I imagine there might be a server-side solution where we use something like dragonfly to dynamically size assets as they are requested. Assuming we can supply the largest version of the asset possible, we could potentially create a service that would let us request a smaller size of the asset through the url.

@steckel
Copy link
Author

steckel commented Mar 2, 2012

@jeremyruppel I also think using dynamic style sheets like less's embedded javascript feature is a viable solution though if it puts a bad taste in my mouth mixing js and stylesheets (I believe @OscarGodson feels similarly).

Also, in order to get dynamic stylesheets to work, we'll have to have the less compiler running on the client side unless the server can some how be intelligent enough to gather the information needed (pixel density, bandwidth, resolution) and render the less into css before even touching the browser. Kind of complex but, straight forward.

I'll definitely attempt to play with this solution to create a proof of concept. It may be the missing link before we have a true hi-res/responsive way of handling assets for the web.

@mayognaise
Copy link

Hello, wow really good thought! I like the markup. Also window.connection.speed and dynamic CSS.

I hope I'm not missing the point, but I'm wondering if we can use this feature easily, like how Lazy Load does. So after calling $("img.res").xxxload(); , all of the elements are going to change with right res images. It could be passed through many options such as suffix, effect, connection speed limit and stuff. Hmm, I'm just saying...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment