How to work around the Mobile Safari image resource limit

Thijs van der Vossen

Because of the memory available on an iPad or iPhone, Mobile Safari has much stricter resource limits than most desktop browsers.

One of these limits is the total amount of image data that can be loaded on a single HTML page. When Mobile Safari has loaded between 8 to 10 MB of image data it will simply stop displaying any more images. It might even crash.

This limit doesn’t affect most websites since it’s generally a good idea to keep web pages reasonably small.

However, you can get in trouble with big image galleries and slideshows or with web applications that load new data asynchronously, for example to enable smooth ‘native’ transitions between different sections (yes, you can do those Flipboard transitions with Mobile Safari).

Screenshot of The Big Picture with unloaded images Screenshot of Things Organized Neatly’s archive page with unloaded images

When the images stop loading: The big Picture and Things Organized Neatly’s archive page. Let’s fix the blue squares.

It would be entirely reasonable to expect to be able to work around this limitation by just removing image elements you no longer need:

var img = document.getElementById('previous');
img.parentNode.removeChild(img);

Doesn’t work. For some reason, the actual image data does not get released when you remove an image element from the DOM (or an element containing one or more image elements). Bummer.

Wat does work is to set the src attribute of the image element to the url for a different (much smaller) image file:

var img = document.getElementById('previous');
img.src = 'images/empty.gif';

When you replace the src attribute, the old image data gets released. Eventually.

I’ve tested this technique thoroughly and it turns out there are some things you have to be aware of:

  1. The image data doesn’t get released immediately after you set the src attribute to a different image. It can take quite some time for the garbage collector to actually free the memory. This means you can still get into trouble if you add images too fast.

  2. There’s no way to get Mobile Safari to load any additional images once it hit the image data resource, even if some or all of the loaded image data gets released. This even seems to persists across page reloads which means you may have to restart Mobile Safari while testing this technique (this nearly drove me insane).

  3. If you also want to remove the image element from the DOM, you need to make sure the element cannot be garbage collected immediately after you’ve changed the src attribute. The old image data might not be released in this case. This is what works best for me:

    var img = document.getElementById('previous');
    img.parentNode.removeChild(img);
    img.src = 'data:image/gif;base64,' + 
          'R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
    window.timeout(function() {
    img = null;
    }, 60000);

    As you can see I’m using a data URI for the replacement image. Credit for this tiniest GIF ever has to go to @pib.

If you only remove the image elements, the iPad stops loading after 8 images. With Zepto’s asset plugin, it just keeps going.

When I explained this technique to Thomas Fuchs last week, he immediately added it to his excellent Zepto mobile WebKit framework. This weekend, I contributed a functional test you can use to try this for yourself.