Preload image before revealing the element

Hey,

I was wondering if there is a nice method to only show/reveal an image and its accompanying elements when it is fully loaded on the client side.

Case scenario: I want to display a list of images and each image also has a description in a <p>. At page load, you quickly see a bunch of descriptions, but the images are not loaded in yet, but quickly thereafter those start to load in and everything looks normal, as can be seen in the video below:

That looks terrible imo and I want the text (and image for that matter) to only be shown when everything is loaded. I sadly have no clue how to get the “image is loaded” state from the image tag. Would simply transferring the image from the server in base64 or bytes solve the problem?

Thanks in advance!

I think you need to listen to the load event on each <img> using Html.Events.on. For completeness, you might want to listen for error (in case an image fails to load) and have a timeout as well, so people at least can read the text if they’re on a bad network.

3 Likes

Beware that if you do that then the images wont be cached by the browser and will be reloaded every time.

That’s a very good catch, I hadn’t thought of that yet. Do you by any chance know how to store/cache base64 strings? If not, I’ll google around and let you know in case I’ve found something.

You can use the widthand height attributes of the <img> tag to avoid such flickering.

I wouldn’t recommend to use base64 except for certain controlled things when there is no alternative. In this case, the classical solutions are the ones already provided:

a) Use html events, as @lydell says. This way you can do transitions or other stuff related to having the image upfront once the images are loaded.
b) As @hans-helmut states, set the with and height attributes.

On the other hand, I have not enough experience with elm/bytes, but maybe there is a way to use it together with elm/http in order to achieve what you need purely in elm, but I would go for either a or b.

1 Like

As @francescortiz said I would avoid using base64 images. You cannot cache them and they also make images bigger as base64 encoding is not as efficient as binary.

1 Like

I agree, looks like option a is the go to option for me. It would be interesting indeed to see if I can use elm/bytes together with elm/http, but then I will run into the cache problem again I suppose.

Indeed another disadvantage. Thanks for reminding me of that caveat :slight_smile:!

1 Like

This is something I’ve run into while working on my Elm photo album, though in my case I’ve been trying to take it one step further, and track not just whether the image is loaded, but progress along the way.

My tests have shown that most major browsers don’t support onProgress events on <img> elements. :frowning:

I tried using data URLs, but in my use case – thumbnail pages with dozens or sometimes hundreds of <img>s – the performance of keeping all those strings in memory was very poor.

Thus, I’ve taken the approach of first fetching the image’s URL with the standard Http.get , tracking its progress, and then when that completes I switch from a placeholder <div> to the actual <img> element.

This is either elegant or hacky depending on your point of view. :slight_smile: But in practice, it seems to work pretty well.

I actually haven’t pushed my latest code on this front yet because I’m still shaking out some bugs; what’s on github now does use Http.get but doesn’t track progress. Hoping to push a newer version soon though!

2 Likes

I finally got things working the way I wanted. This commit has my comments trying to explain what I arrived at and why I did.

2 Likes

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.