administration mode
Pssst...Ferdy is the creator of JungleDragon, an awesome wildlife community. Visit JungleDragon


JungleDragon's redesign - iteration 2 »

FERDY CHRISTANT - JUL 6, 2012 (08:49:28 PM)


I'm redesigning JungleDragon to have a modern, responsive front-end, and I'm doing so publicly. Today I present you iteration 2. In iteration 1, I shared a basic layout framework, a text-only site that adjusts its layout according to the size of your screen. Since then, I have taken in some new learnings, applied a few fixes, and simplified things where I can. 

On to iteration 2, which is about one thing only: Responsive Images. Images that adjust to the size of your viewport. Images that load the correct file size for your context.

About responsive images

Before I demonstrate the result, there's a few things I'd like to say about this topic. First, images are obviously the holy grail of any photo site. So I was a little surprised that when I was checking how the big guys are doing responsive images (Flickr, 500px, 1x), the simple answer seems: they don't. It's relatively new ground, although it should be said that those sites have kick-ass mobile and tablet apps. I'm talking about the mobile web though, not apps. We're all figuring out how to best implement this.

And that definitely applies to the web technology behind it. There is no official way to do it that is supported across browsers, so in the meanwhile the community is coming up with creative hacks to implement responsive images. None are perfect, yet many are usable. This overview shows some of the possible solutions.

JungleDragon's responsive images

In this iteration, I've worked on both photo lists (grid) as well as a single responsive image. Let's see what we got. I'll be sharing several screenshots, starting from small screens to big screens. Please do open the live demo to follow along.

Now remember, this is a single mobile site that adapts itself to your screen. If you'd open up that link on an iPhone in portrait mode (or any other device around 320px in width), this is what you get:

As you can see, this concerns a single column of photo thumbs that take up almost the full width of the screen. A total of 12 thumbs is loaded in a universal file size, meaning bigger screens get the same image file. I tried using smaller thumbs for mobile but high-end smartphones have such good screens that the poorer quality was off putting. In terms of vertical sizing, you can see that about 1.3 photos fit without scrolling, more if you slide away the header. This is the screen you get when opening a single photo (by clicking on it):

This photo does not have a universal file size, meaning a better quality than this one is loaded when your screen is better. On this single image screen, you see it again takes up the entire width. This page has two columns, which are placed below each other (see "Column 2" text).

The same is true on Android:

Swell. Now here is what happens when you flip your smartphone to landscape mode. On iPhone:

Because of the increased width, we now have two columns of images, and if you scroll away the header navigation you can see about 4 at a time on a single screen. As for the layout, we know that images can have different orientations and crop sizes. I have decided to force each one into a specific rectangle. This ain't perfect, particularly for portrait images, but something's got to give. Note though that opening a single photo will always respect its original aspect ratio. 

Note that I'm not hardcoding for devices or orientations. I'll prove it. The Blackberry in portrait mode:

Although it's in portrait mode, it still has 2 columns. This is due to the wide and low screen of this Blackberry. And here's another interesting aspect of my solution: it goes beyond major breakpoints. We've discussed 320px and 640px, but the design scales perfectly in all resolutions in between. The images grow to fit. 

Let's move on. The very same photo list on an iPad in portrait mode:

I'm happy with this. Table top photo browsing in a clean grid, easy and large touchable targets.  We now have 3 columns of photos. The other major difference: instead of 12 we now have 24 thumbs. I did not chose multitudes of 12 by accident: the number can be divided by 1, 2, 3 and 4. 

So how does it figure out how many thumbs to load? I'm setting the viewport width in a cookie, upon the next request I can read it at the server side and load the correct amount of images. If the cookie is not yet set (for example when you first open the page), the fallback is 12 thumbs, which is no disaster.

Now let's move that iPad into landscape mode:

This is the first "desktop" breakpoint. As of a width of 1280 pixels, we get a two column layout. Column 2 is empty, this is just a demo. We still have 3 columns of photos, but now they are slightly smaller.

From 1280 pixels to 1600 pixels in width, everything will grow in proportion to your screen. At 1600 pixels, we arrive at the final major breakpoint: HD desktop (or TV, or whatever):

As you can see, we now have wider columns, and more image columns, 4 this time. Because column 2 is empty, this screenshot does not do this layout much justice. It's quite fantastic compared to opening JungleDragon currently on a big screen. 

Internet Explorer, the anti-browser

Regular readers know that I hate Internet Explorer, every single version of it. But it can't be ignored, so here's the deal for IE. IE9 is fuly supported. IE6 and 7 are currently not supported. What about IE8? Since it doesn't support media queries, the fix I would have to write would be huge. So I didn't. In IE8, you get a fixed width design optimized for 1024 pixels of width:

In IE8, you can resize that screen all you want but nothing will change. It's fixed width. That's quite a difference from the other browsers, but it's honestly not that bad if you consider that JungleDragon currently is entirely fixed width, across all browsers and screens. 

Responsive images, for real this time

I've talked about two responsive image aspects in the demo above: scaling images into columns, and loading the appropriate amount of images. The third aspect, and this is actually the heart of the matter, is loading the correct image format. You don't want to load a 1MB photo on a smartphone and you don't want to load a crappy small photo on a HD screen. So how is this solved?

Responsive image loading is not applied to the thumbs, it is applied to the page where you open a single photo. It works as follow:

  • As I told you, I'm setting a cookie that stores your viewport width. If the cookie is successfully set, the server uses it to load the correct image format the first time right. No tricks, no odd HTML, just plain old img tags with a valid src attribute.
  • If the cookie is not set, the server does not know what the size of your viewport is. In this case, the smallest file size is used as a default in the spirit of "mobile first".

Now here comes the cool part. Say the cookie is not set and you're on a large screen. The small image will be blown up quite a bit, with visible quality issues as a result. However, javascript logic will detect that you're on a large screen, and will immediately load a higher resolution image in the background. It will replace the small image once loaded. In essence, it's progressive image rendering. A similar implementation is currently active at Facebook: when you open a large image, it will load a low quality version first, and then quickly render a better one. In this demo, there are 3 file formats it can load, which one is loaded depends on your viewport width.

Remember, this mechanism only kicks of if the server does not know which image to serve in the first place. I'm happy with this mechanism. It's not perfect, but it has major advantages:

  • No funky HTML elements, just plain old imgs
  • Most of the time images will be served first time right, no double loading
  • 3 file sizes optimized for major breakpoints
  • Progressive rendering as an elegant fallback

There's one border-case that is problematic: large screens with javascript disabled. They will get poor photos because both the server and javascript have no idea which one to load.  It's a downside, but I accept it, knowing that most other responsive loading mechanisms have far bigger problems.

The second downside is that this solution lacks bandwidth testing. It assumes large screen = big bandwidth. That may not always be true. It often is, but not always. Although there are bandwidth testing solutions in javascript, I'm starting out simple. 

Wrapping up

Developing this solution, which involved trying many different approaches, was not painless. I've had moments where I was hoping I could just go back to the simple life of producing fixed width designs. I'm also realizing it can take me months to fully implement this in JungleDragon.

But the pain has value. It's tremendously educational. But above all, it's worth it. Seeing your designs working across several devices without actually hard-coding for them brings a tremendous sense of accomplishment. That's enough to keep me motivated. The road ahead is long, but I believe the end result is exciting. 

Having said all that, I'm of course anxious for your feedback on this second iteration. Clap at it, laugh at it, test it, criticize it, bring it on!

Share |

Comments: 6
Reviews: 1
Average rating: rating
Highest rating: 5
Lowest rating: 5


JUL 7, 2012 - 06:05:01 AM

comment » You might want to rethink using the img element on an iPad. There are known memory leaks. Many photo gallery sites use a background image on a div element because background images don't leak like foreground img element images. You will have to use inline styles, which I hate, but what else can you do?

Using the img element can cause an app that worked on the iPad 2 to fail on the new iPad. Also you can take advantage of the retina display using a background image and setting background-size to the lower resolution iPad. The new iPad won't have to up convert the image for the retina display and even though you've defined it as a smaller image it will recognize it as a higher resolution image than you've defined. Of course as you said that doesn't take bandwidth into account.

I wonder how Netflix or Hulu determine the speed of a connection. Maybe an ajax call to determine bandwidth speed for high resolution mobile devices?

I've found your posts to be helpful and I'm looking forward to future posts. «


JUL 7, 2012 - 10:20:33

comment » Personally, I don't give a monkey's about the iPad. Fixing for an img leak is not Ferdy's responsibility. What happens when the iPad fixes their stupidity?

But I will throw in another reason for why you should consider using a background div and that is image theft. It's so easy to right click and "Save Image" when using normal images. It's far harder when it's presented as a style sheet object. «


JUL 7, 2012 - 12:39:49

comment » @Tanny: Thanks for the feedback! I'm not familiar with the image leak problem, do you have a source/more info on the problem? I'm using an iPad 1 and 2 quite a lot and never came across this problem. I'd like to learn more about it.

I tend to agree with Dragon though: the whole web is made of img objects, a device not capable of handling the bare bones of the web is not a reason for me to change my code drastically. As for Retina support: I'll get to that when I solve all other responsive image challenges.

Having said that, I do see the advantages of background images, they give more flexibility in image positioning as well. Still, the classic img approach makes for a very semantic solution, SEO friendly, and compatible with all kinds of services that depend upon it (sharing widgets for example).

Bandwidth testing indeed is typically done using ajax, where a sample file is downloaded in the background. «


JUL 7, 2012 - 12:48:29

comment » @Dragon: Concerning image theft:

- Partly, I want to support the "good theft". Meaning, I'd like Google to discover the photos, and I also encourage social sharing. Both are forms of theft, but the overall consensus is that they are good.

- As for blocking the downloading of images, I will disable right-clicking. With slightly more effort you could still download the image or screen grab it, but the same is true when you use a background image: right-click->view background image->save as...->done.

- Users getting past this discouragement to download, will only be able to download photos of a limited resolution, not the original photo.

- Realistically speaking, users who are truly protective of their photos (because their income may depend on it) also have an own responsibility in protecting them. The point of photo sites is to share them. To share them without giving away the original. Typically you will find such "serious" users shrinking images and watermarking them, both visually and in exif.

All in all I think I'm being reasonable in protecting the right of photo owners, as per the general consensus on the web. In fact, a some big photo sites are a lot less protective than JungleDragon. «


JUL 8, 2012 - 04:20:29 PM

comment »

I ran into this problem with an offline html5 web app. It would run out of memory and crash on the ipad 1 and 3 but not the iPad 2. changing from foreground images to background images solved most of the problems. I still get the occasional out of memory the crash problem with the ipad1. This article has helped too. «


JUL 8, 2012 - 20:28:51

comment » @Tanny: Thanks for the extra info. A surprising limitation indeed. I do think the limit does not apply to what I want to do. The progressive image loading technique I'm using concerns a single image on screen. I'm not doing progressive image loading on thumbs. As for the size of that single image, it's largest version will be around 0.5-1MB. Whatever I do, I'll be sure to test on the iPad1 and 2 as I have those around me. For the iPad3 I'll use the simulator. «

Was this document useful to you?
rating Awesome
rating Good
rating Average
rating Poor
rating Useless
required field
required field HTML is not allowed. Hyperlinks will automatically be converted.