Serving up different sized dynamic images based on device resolutions

Serving up different sized dynamic images based on device resolutions.

Jason and I were working on an app where we needed to render dynamic images of several different sizes for different mobile devices, depending on device resolution.

Our scenario was analogous to the following:

Let’s say you are an engineer for Twitter and you need to display a user’s avatar on their show page, but you need to serve a small, medium, or large image based on the resolution of the device accessing the page.
This is a potential candidate for CSS media queries, except that the image url needs to be obtained from our User object (in Ruby).
Let’s cross that bridge when we get there and spike on an initial proof-of-concept.

Pretty straightforward stuff, especially if you’ve followed the Responsive Web Design (CSS media queries) trend.
The interesting thing to note here is that when putting the background image in the stylesheet, the asset does not get requested until you resize your browser to the size that uses that image.
Go ahead and load this page in a web browser, open up the network panel, resize the display, and watch the asset size change and different requests getting fired off. That’s exactly what we want!

Okay, great. But, although it would be glorious, not everyone is going to have Dog Fanny Pack for their avatar. We need to call some ruby method on some ruby object to get the image (e.g. user.avatar.path).
Not really something you can do from within the stylesheet. Alternatively, you wouldn’t want to move the background image reference to the view because then it gets loaded as soon as the page loads, regardless of the screen resolution.

To make this puppy (pun intended) dynamic, we create a little proxy. See below:

Users controller

We create an action, called avatar, on our users controller (you also create a separate avatars controller) that takes a size parameter. The avatar action first looks up the user (You don’t get to see how ’till later),
then it grabs the size from the url and renders the user’s avatar for that size.

Quick aside

You may notice this action isn’t really on the member (i.e. no user id), even though it should be. We’ll get to that in a second.
You may also be thinking of alternatives to using send_file. Jason and I experimented with redirects, but ran into caching issues. I am open to suggestions on these topics, so feel free to post feedback in the comments or submit a pull request to the demo app.

Back to business

Now all we have to do is call our proxy image/action in the stylesheet, see below:

In our case we always had the user id in the page that used the avatar. If we tried to implement this on the listing page… Well it wouldn’t be pretty.

While this isn’t a silver bullet solution, it’s a cool concept and can be applied to many different applications. I call it the “responsive-css-background-fake-image-proxy” pattern.
Okay, maybe not, but to recap, the main components are:

Use CSS media queries to target different device resolutions.

Reference the background-image proxy url in the stylesheet, which only loads the image size needed.