2

I have the standard "responsive image serving" problem, but with some complex twists. I expect I'll need to build my own solution to the below, but it's a few months down the line so I thought I'd bring this by the community now for help with my approach and getting started. I also think the solution I'm looking for would have pretty wide appeal, so this could be valuable to the community as a whole.

The problem:

  • We'd like to provide users with images, embedded videos, etc (anything that takes a lot of time/bandwidth to load and takes less when lower res) but change the loaded dimensions depending on the size the element is actually allocated on the page. This is basic "responsive image serving" applied to a few other types of assets (though since we provide lower-bandwidth file versions to mobile devices, I think this also falls under "adaptive design"). But don't worry about other types of content for now, let's focus on images.

  • We need to determine the appropriate max-width for a each specific asset placement, for each screen width breakpoint, without providing this info as configuration.

I'm creating a platform that will serve pages relying on HTML templates from many different parties. Images can be served from anywhere on the page, and pages can use any styling system they want, so we have no idea what the appropriate size for an image is just by looking at screen width. We need to actually evaluate the max width of the placement at each supported sizing breakpoint. Sure, this could be done manually in advance given a design template, but let's assume that's too much work for these 3rd parties.

For example, in Twitter Bootstrap 3 an image contained in a col-md-8 should be at most 720px width when browser width is < 768, but if it was in a col-sm-8 it should be smaller than 470px. And if we're using a different framework altogether these would clearly be different too. I need solution that can take into account everything the CSS is doing automatically, because I have no idea what the CSS will do.

  • We can't do any processing during the image request. We rely on a CDN (Cloudfront). They are not going to implement our custom code on each of their edge locations, and I don't want a visitor in New Delhi or Berlin to have to send yet another request halfway around the globe, for every sized asset, before they know what the final url is. So that rules out solutions like this controller-based solution and the PHP adaptive-images script.

  • We need this to be fast. There's a good amount of wiggle-room on the server side, since caching is so easy and flexible with Rails 3 & 4. But we probably can't use jQuery.width() on every element for performance reasons. After all, the entire reason we're serving responsive images is to decrease perceived page load time. But we do have access to jQuery in general, and we could probably load up Modernizr all the time if we needed to (currently only included for low IE with conditional HTML).

  • We don't trust User-Agent headers enough to base our browser width on them. I love the idea behind mobvious 1, 2 and its friend responsive-images, but there are SO many versions of browsers on SO many different devices out there. How complex would it be to build a truly reliable system to determine browser width on this, as opposed to directly calculating it using JS?

  • Clients without javascript (and thus crawlers) will need access to an image. Easiest solution here seems to be to include a <noscript>....</noscript> with the canonical, largest version of the image inside.

The solution It seems like the only way to do this is to:

  • Have the server pass all the available sizes, then calculate the width of each element on the client side using jQuery in some performance-efficient way (maybe using $.css_width() or some sort of specialized script). So server would create:

<span data-respv-img-id="picture_of_unicorns"></span> <noscript data-respv-img-id="picture_of_unicorns" data-img-720- url="//cdn.example.com/assets/picture_of_unicorns_720x480" data-img-320-url="//cdn.example.com/assets/picture_of_unicorns_320x260" data-img-120-url="//cdn.example.com/assets/picture_of_unicorns_120x80"> <img src="//cdn.example.com/assets/picture_of_unicorns_720x480" alt="Magical unicorns"> </noscript>

And if we're on a small screen and only the 120 fits, the JS would turn this into:

<span data-respv-img-id="picture_of_unicorns"> <img src="//cdn.example.com/assets/picture_of_unicorns_120x80" alt="Magical unicorns"> </span>

  • OR have the server do some sort of pre-processing, so it knows exactly what size image fits each placement on each browser width, and delivers:

<span data-respv-img-id="picture_of_unicorns"></span> <noscript data-respv-img-id="picture_of_unicorns" data-img-1200- url="//cdn.example.com/assets/picture_of_unicorns_720x480" data-img-1024-url="//cdn.example.com/assets/picture_of_unicorns_320x260" data-img-768-url="//cdn.example.com/assets/picture_of_unicorns_120x80"> <img src="//cdn.example.com/assets/picture_of_unicorns_720x480" alt="Magical unicorns"> </noscript>

And we end up with the same thing as the other approach. But this time jQuery's job was much easier, as we passed all the sizing work off to the server. But this requires loading up a full browser stack on the server side to generate each request. That's ok with caching, but sure does bring a lot of complexity along.

Note that both of these solutions would allow for scroll-based image loading, which is another aspect I'll need to implement, but not something we need to discuss now.

Long story short: Which approach would you recommend? Can you think of a better way?

Community
  • 1
  • 1
zrisher
  • 2,215
  • 1
  • 16
  • 12

0 Answers0