Steve Desmond


Responsive Images

Tuesday, October 27, 2015 @ 2:31pm

OK, finally time for a technical blog post!

Some background: previous iterations of this site have used what I would call, "server-side responsive images."

  1. Images were requested via JavaScript, and the image URL included the screen dimensions as query string parameters (e.g. "getImage?id=123&x=1280&y=720")
    • This JavaScript was also doing the math to optimize for "high-DPI"/"retina" displays
  2. The server would take the image ID and screen resolution, and find and return the highest quality image for it
    • If one didn't exist, it created it on the fly

I'll save you the details of the ImageRetriever and ImageCreator, but suffice to say they're pretty complex. One of the great things about open source, however, is if you actually want to, you can check them out!

Fast forward to open web standards

I only learned quite recently (maybe this past summer) about client-side responsive images, specifically the "srcset" and "sizes" attributes on an "img" tag. Basically, we're going to take all that complex logic that I had written in my server-side ImageRetriever class, and have it baked into the browser.

It took me a while to wrap my head around, using this 10 part guide as a reference, and I since then saw another presentation that wasn't as straightforward as I was hoping, so my goal here is to have a single-page "how-to" for client-side responsive images, using <img srcset="..." sizes="..." />.

So let's dive in!

Here's our image tag: this is the actual code used for my headshot up at the top of every page here.

Let's go through each of the attributes:

  • src: This is the backup/default, in case the user's browser doesn't support responsive images (IE11 and older, stock Android browser before 5.0) -- this is exactly what it would be if you weren't doing anything at all with responsive images
  • srcset: Here is our list of "alternative" images, and their widths (e.g. steve-0100.jpg is 100px wide, steve-0200.jpg is 200px wide, etc.) -- note that these are actual individual files/URLs
  • sizes: Here's where things get a little confusing...this is how big the image should be on various sized displays. Note that this does not actually set the size -- that's CSS' job -- this simply lets the browser make a smart decision about which file it should download.

Now let's look at several examples of what happens on different devices, and why:

  • My Desktop (1920x1200, non-retina)
    1. Check "sizes": are we 767px wide or less? No, so we can expect the image will be displayed 150px wide.
    2. Check "srcset": what's the best image for 150px wide? steve-0150.jpg
    3. There is no #3, it's that simple!
  • My MacBook Pro (1680x1050, "retina")
    1. Check "sizes": are we 767px wide or less? No, so we can expect the image will be displayed 150px wide.
    2. Check "srcset": what's the best image for 150px wide? steve-0150.jpg
    3. Hold up! We're on a "retina" display, which means 2 "physical pixels" per "CSS pixel." So we actually want an image that's 300px wide (150px x 2). Therefore, our best image is steve-0300.jpg
  • My Moto G (360x640, "retina")
    1. Check "sizes": are we 767px wide or less? Yes, so we can expect the image will be displayed 100px wide.
    2. Check "srcset": we're on a retina display, so what's the best image for 200px (100px x 2) wide? steve-0200.jpg
  • Me using Firefox Dev Tools to mimic my Moto G on my desktop (360x640, non-retina)
    1. Check "sizes": are we 767px wide or less? Yes, so we can expect the image will be displayed 100px wide.
    2. Check "srcset": what's the best image for 100px wide? steve-0100.jpg

Pretty straightforward, right?

A little more advanced

Same concept, just a little more going on here -- this is code from the Photography section of this site:

  1. We've got a whole lot more images available (which were all pre-rendered using ImageResizer) to ensure that:
    • Everyone is getting the highest quality image for their display
    • No one is using more bandwidth than they have to (e.g. downloading a huge image on a tiny screen)
  2. We've also got some new/funny stuff going on in the "sizes" attribute:
    • 100vw: if the screen is smaller than 768px, the image will take up the entire width of the screen (100% of the viewport width)
    • The middle two sizes match Bootstrap's small and medium breakpoints, and their expected image sizes account for container padding
    • If all else fails (we're on a large screen) use Bootstrap's large container width, minus padding

Wrapping it up

Obviously some of these values are pretty specific for my site, but hopefully you get the point:

  1. The sizes attribute helps the browser to determine how large the image will be displayed, based on the viewport
  2. The srcset attribute contains all the images and their respective widths
  3. The browser combines the "size" result with the viewport information to determine which image from the "srcset" attribute to download

I hope this was helpful in being a more concise tutorial on responsive images than what else is out there.

I may, in a future post, get into the TagHelper that dynamically generates these img tags.

Thanks for making it this far -- I'd love any feedback you may have!


Now With More Twitter Cards!

Thursday, October 1, 2015 @ 10:04pm

This is the most meta post ever.


The Blue-Green Kestrel

Friday, August 21, 2015 @ 8:37pm

I've had some issues keeping the IIS application pool active for extended periods of time, probably something to do with running on pre-release software, but I figured I'd take it as an opportunity to switch to Kestrel, the web server that's part of the ASP.NET v5 project.

IIS is now simply acting as a reverse-proxy, passing requests and responses to and from kestrel, much the way that nginx is used as a Docker front-end.

I've also switched to a blue-green deployment pattern to eliminate downtime during upgrades.

Not that I've got the visitor volume that would notice short outages, it's more that these are the things I would love to do as part of my day job, but can't.

Still on my to-do list is to create a service to make sure kestrel stays up, and restart it if it fails.

I'm also planning on moving my codebase to a public GitHub repo, once I confirm there is no sensitive information from the commit history.

So stay tuned, I'll be starting to share technical details, from code to architecture, at all levels of the stack, as things start to settle!


Now With More CMS!

Tuesday, August 11, 2015 @ 10:34pm

I've been quietly working behind the scenes, pushing out updates. It may surprise you that up until recently, the content of this site was actually hardcoded into server-side views, which meant I would have to recompile the entire site for each of the below new posts!

I have since implemented a simple CMS/blogging engine, with a quick-and-dirrty publishing/admin interface, so you can expect updates more than once a month going forward! My intent is to share with you some of the quirks that ASP.NET 5 and MVC 6 threw at me, hopefully helping make your life easier, should you decide to build something with these fantastic frameworks.


The Office

Tuesday, July 7, 2015 @ 10:19pm

Almost three years and two children later, I finally have a corner (literally) of the house to call my own. There are still some finishing touches to be done (currently no doors, etc) but it's enough to at least move into.

A before-and-after from the doorway, facing west

The north wall and its many built-in panels: from power to fresh air to gigabit ethernet to 7.1 surround sound

South wall, now with a frosted window so I don't need to look at the ugly under-side of our deck

Facing east back toward the entrance, closet under the stairs on the left

As I tweeted, I'd be lying if I said I wasn't pretty F'ing proud of myself!


There's an App for That

Tuesday, June 16, 2015 @ 9:22pm

I gave a talk!

My very first talk, in fact, at a conference. Last week, during HighEdWeb NY, I presented "There's an App for That: Creating Cross-Platform Native Experiences Using Open Web Standards" -- isn't that a mouthful!

You can read the full abstract here, but it's basically about using more advanced HTML5 / CSS / JS APIs to make your web apps as fancy as those new-fangled native ones.

You can check out the slides in the Talks section, or enjoy a recording of it on YouTube.


Hello, vNext World!

Thursday, May 7, 2015 @ 10:33pm


This brand new site is running on ASP.NET 5 "vNext" (beta 4) and will become a home for my many thoughts.

Check back soon for those, but for now, click on that camera link in the menu up top to get to my old photography site (also now running ASP.NET 5, with a new Angular front-end), or follow me on Github and/or Twitter!


© Steve Desmond