61 comments

[ 2.4 ms ] story [ 115 ms ] thread
This is amazing, but I feel like there is something fundamentally lacking from <img> if you have to do all this bullshit just to get an image to display.

Why can’t the image and DOM spec be upgraded to include lazy loading and touch to download? I can’t think of a use case where you wouldn’t want this.

Read the whole thing. As is typical with committees, they harp on about crap that doesn’t matter to 99% of users, and thus any viable solution gets delayed indefinitely. So I guess we get shitty image loading across the whole web, oh well.
That's kind of the browser's responsibility, really. The image element already covers what is required to instruct the user agent that there a) is an image resource and b) what its location is. It's then up to the browser to do the right thing with that data. It's nice that people are finding ways to preempt that in case the browser they're in is dumb as dirt, but it's really not the role of the spec to tell user agents how to deal with loads of images. If I'm browsing my gigabit intranet image repositories on any of our workstations, I don't want my user agent to be "intelligent" and just load everything, because it can. If I'm on LTE mobile, I want my browser to be a little smarter about swapping in/out image content. If I'm on 3G, I don't want the browser to load any images at all unless I tell it to. But those are my wants, those are not things the spec should "ordain" user agents must (in the spec definition of must) do.

React components like these are nice, but the real question is why doesn't your _browser_ already do this. Not "why doesn't the spec say what needs to happen", but why haven't Microsoft, Google, Mozilla, Opera, etc. implemented network-and-content-traversal-appropriate image handling? (one answer might be "because apparently users don't actually ask for it enough", but I honestly don't know).

Because there’s no way to standardize the behavior across user agents to the extent necessary that developers could actually rely on it producing a consistent experience across a large user-base.
Conversely, there is also no way to standardize which solution to use to the extent necessary that developers could actually rely on it producing a consistent experience across a large user-base.

You don't need standard behaviour, you just need _good_ behaviour. And if every browser does that differently, but it's appropriate to the network speed and processing capabilities, then as a dev the issue of "making sure images load appropriately" becomes as irrelevant as "making sure your webfont actually loads" has become in the modern browser landscape.

Downloading all the images provides a good user experience. If your intranet has a GB of images on a single page, that's on you - even if browsers did as you suggest, any older browser would still saturate your network link.

These fancy image placeholders seem more designed to save on CDN costs than to provide a good UX.

I think you misread what I said as "I want the browser to load all the images, all the time" instead of "I want the browser to download and render in ways that are appropriate to the constraints of the network and processing power, not have to rely on a million folks each inventing their own lazy-loader".
Perfect opportunity for a reusable web component that anyone could consume
I think this is a typical lifecycle. The community will be a magnificent shim or two, then the committees will wait and see if it's a winner, then start adopting the key elements. That's why nearly all of jQuery is now supported natively by browsers and why we have <video> tags instead of flash.
Well this is very cool. On my MVP projects I'm happy to get any of those things to happen.

I would LOVE an angular service that did this that I can re-use. If only I had the time to fork this and make it work... May need to explore this over the weekend.

Thanks for putting this together!

It would be helpful if the repo stated why this was ideal - and as opposed to what?
If you click through it actually tells you all the things it provides which you wouldn't get with a vanilla img tag.
Ah, didn't realize it wasn't a top-level readme. For the lazy:

> I need React component to asynchronously load images, which will adapt based on network, which will allow a user to control, which image to load.

It would be cool to optionally integrate SVG placeholders, a-la: https://medium.com/@jmperezperez/using-svg-as-placeholders-m...

(previously discussed: https://news.ycombinator.com/item?id=15696596)

That seems like it would require a compile step with a file loader, which is generally doable but means you need handling for (for example) Webpack vs. Parcel vs. whatever else.
Wow this is great.

Right now I'm using a homemade <ImgWithPlaceholder src={src} /> that displays a generic gray PNG on 404 or src null.

I'll definitely try your lib as a replacement. I'm excited about the out-of-the-box lazy loading and the LQIP (never heard before.)

Why do I love stuff like this sooo much? (I really do)

Consider the yak shaved. :)

I know this'll get downvoted, but this looks like an awful lot of work for... displaying images in a browser. As other HNers have said, it feels like the browser should be doing this work rather than having to create round about, convoluted JS solutions to deliver simple functionality.

Plus, I don't get what's exciting about this. But I'm also not a react guy - and this does nothing to make me consider picking it up. Which, is counter to all the cool JS libraries i've pulled into projects over the years, which naturally induced a desire to learn more JS.

I guess if you're hyper focused on react or frontend js in general, this sort of stuff might be more appealing and relevant. but dear god I've got way more important/interesting things to do than spend a day getting images to render in the browser. Nor does this do anything to lower the barriers of entry for people with an idea and a desire to build something. Sometimes I wonder if that's a design intent.

anyway, sorry for the rant. Great job identifying/solving problems, but i don't get the appeal.

I'll reply because it seems like 25% of every thread I've read on front end development in the past 5 years has a comment like this.

This library doesn't really have anything to do with React. Just because it is implemented in React doesn't mean that React needs this, over say Vue or Angular or VanillaJS or w/e "cool" library you like. In fact I would say the existence of libraries like this should make you want to adopt React over a library with less adoption.

I would also suggest you be more open to the idea that these kinds of things matter quite a bit when you are operating at scale. This type of library isn't really intended for the use case where spending time making optimizations isn't important or interesting.

> Plus, I don't get what's exciting about this.

Substantially cutting down loading time for a page with 800 high-quality images while still being able to write components in a completely declarative manner.

This is about performance and UX. Respect for the user. Yes, browsers should be doing this. But they don't. So other than the obvious, what do you propose?

> this does nothing to make me consider picking it up. Which, is counter to all the cool JS libraries i've pulled into projects over the years, which naturally induced a desire to learn more JS.

For shame. What this tells me is that you essentially don't care about your users. The notion of this being something only react/frontend developers care about is also quite off-base. Lets include all the "cool" JS libraries under the sun until the page is bloated, but definitely not the ones that try to make the site perform better... ? Yeah not a good attitude.

Perhaps if you imagine yourself on a metered connection, navigating to a page with a bunch of hires images, wouldn't you appreciate the work the developers put into making the site a better experience for you? That respect for the user is the appeal.

I don't get why a comment like this is downvoted. The commenter is simply saying that he doesn't understand the hype. This site is getting nearly unbearable with the groupthink, particularly around specific tech or frameworks.

/meta

On this particular issue, I will go further than my parent and say this does not represent a significant step forward in the scheme of things. The problem being solved here is largely akin to a problem I had to solve 15+ years ago with Vanilla JS. It is positively nuts that we are celebrating a "fix" for it all of these years later, and that we are investing so much time on what should be routine by now.

Anyone who is genuinely excited about this should sincerely be asking themselves if it's a good thing that a lengthy post/fairly involved component for sanely displaying images in a browser is the state-of-the-art for Webdev in 2018.

Yes, I get it: browsers don't do x or y. So, yeah, let's add more libs, more frameworks, more shims, more specs...more, more, more. It's almost self-parody by now. Look at the average Webapp of any semi-significant complexity. It is such a hodge-podge of code, languages, technologies, build steps, etc. that it's a wonder any of it works.

I think it's time we all took a step back and ask, "what are we doing? Is this the right model? Is there a better way?"

As someone who's been here from nearly day one, there has been groupthink around specific tech and frameworks from nearly day one. :)

It's not a big deal. Just correct the downvotes and ignore the vocal comments.

I identify with your point of view on this topic. But the way to correct the situation isn't to write a rebuttal here. The world only notices better solutions when they exist, so creating them is step one.

>But the way to correct the situation isn't to write a rebuttal here. The world only notices better solutions when they exist, so creating them is step one.

Thanks, but I've clearly not made my point! I am saying that we don't need to each run off and create more solutions as that's how we got here in the first place. That is, we can't solve the problem of too many "solutions" by creating more solutions.

So, I think step one is to step back, all take a breath (devs, browser-makers, etc.) and look at creating a reasonable, cohesive platform for proper Web-development, free of the legacy baggage of a static document-based foundation with reams of duct tape on top.

>> So, I think step one is to step back, all take a breath (devs, browser-makers, etc.) and look at creating a reasonable, cohesive platform for proper Web-development, free of the legacy baggage of a static document-based foundation with reams of duct tape on top.

Lol... this is way easier said than done. The ironic thing is, this has been attempted several times. In fact I would argue this thinking led to the React ecosystem.

( I didn't downvote the parent )

> The problem being solved here is largely akin to a problem I had to solve 15+ years ago with Vanilla JS.

Of course these problems (multiple!) can be fixed with vanilla js. They all have been, separately, each in their own libraries and stackoverflow posts and custom vanilla code on every project in the past couple decades. The linked page does an excellent job of pointing out the libraries and SO posts it's utilizing to resolve these issues.

The purpose of the linked component is to pull in all these vanilla js fixes and tweaks at once, in a way they'll all work together. A drop-in component to utilize years worth of tweaks and fixes, so you don't have to worry about this crap anymore. Doesn't that kind of cover your complaint? We shouldn't have to deal with it anymore. Drop this in, and worry about something more interesting.

> I think it's time we all took a step back and ask, "what are we doing? Is this the right model? Is there a better way?"

I picked React long before most of my colleagues did, and I continue to feel it's one of the most useful libraries in quite some time for browser-based javascript development. Mostly because it allows for something like this very library - drop-in and move on to something better.

I was also a huge fan of jquery - not because I couldn't do what jquery was doing for me, but because I was tired of doing it repeatedly for different browsers and for each and every project. Same goes with prototype.js when it first came out, though I hated how it modified the underlying objects.

If I'm understanding your post correctly, I feel like these are all attempts to resolve the issues you're speaking toward. To allow us to stop dealing with cross-browser, cross-device, 2-cans and a string connection issues that, ideally, our browsers should be handling for us.

At least we don't have to rely on flash to replace missing browser functionality anymore (I say that as someone who absolutely loved ActionScript3).

>The purpose of the linked component is to pull in all these vanilla js fixes and tweaks at once, in a way they'll all work together.

Is it acceptable that this is the state of the art? That, 15-20+ years on, we are fixing the same problem and, further, that we are doing so by rolling a bunch of cruft into yet another framework? Is this really what we are shooting for?

>A drop-in component to...

>Drop this in, and worry about something more interesting

Drop it in after learning and adopting a fairly heavyweight framework that forces you to code to a completely different paradigm. Do we really think this is an acceptable solution for simply displaying images on a Web page? I think that's really telling WRT how far off the map we've wandered.

>Doesn't that kind of cover your complaint?

>I feel like these are all attempts to resolve the issues you're speaking toward.

I think React and others are really symptoms of the problem, which is an impedance mismatch between the static document model that underpins the platform on which we are now trying to build fully dynamic applications.

Rather than continuing to paper over browser deficiencies, there needs to be some collaboration between the webdev and browser communities to define more consistent behavior for common scenarios and a standard component/event based model of the type that has proven suitable for GUI-based applications. The Web standards of HTML, DOM, CSS, etc. should not be first-order constructs in this new model. That is, devs should not work in them directly and, to the extent that these standards are useful due to their currently-broad browser support, they should be generated by tooling. We should be laying out our UIs on canvases in our IDEs with flexible grid layouts, and hanging event handlers off of various events a la Swing.

We need to break the current DOM/old Web model that tells us React and others are good simply because they make the impedance mismatch slightly less painful and paper over some browser deficiencies.

(I didn't downvote your posts either)

I went on a weird tangent with my reply to this comment and just I'm just going to replace it with this. I generally agree with what you're saying as a means forward, but I also think React is a fantastic tool in the meantime.

What we have is, in fact, the state of the art for better or worse. We will get beyond this, but it clearly takes time.

This is a great start. Some lightweight features that would make this even more ideal (for me) would be:

- retina/3x support - support for styled components extend feature (if can be made a lightweight implementation) - maybe default max width of 100% on mobile? - optional ability to overlay an empty full size block so the image cant easily be right clicked and saved

It supports retina/3x. Provide big enough image and it will use it. It takes into account `devicePixelRatio`

> maybe default max width of 100% on mobile?

It is.

> optional ability to overlay an empty full size block so the image cant easily be right clicked and saved

Not sure what you mean, but as soon as image loaded it turns into good old image, so you can do right click

>> optional ability to overlay an empty full size block so the image cant easily be right clicked and saved

> Not sure what you mean, but as soon as image loaded it turns into good old image, so you can do right click

I believe he wants the opposite of that, putting a div over the image so it cannot be right clicked and saved.

(comment deleted)
I hate lazy loading. - bit offtopic: Are there any good browser extensions that stop this behaviour?
Can you explain why?
You have to wait for react to load and initialize on the client before an image can load.
images and everything else bc client-side rendering... not sure how this is an argument for not lazy-loading images though
As an end user it feels slow. If I hold my space bar on a website created in 1995, I can scan the entire page contents.
You'd still have blank spaces where large images are as they're loading on a slow connection
I'm talking about lazy loading that waits until the image enters the viewport. An HTML page created in 1995 loads the images eagerly.
What you are talking about is more like graceful degradation. If server side rendering is used you will be able to see content ASAP, but not able to scroll, because interaction is blocked by JS. But if you will visit page with JS disabled you will get what you want, because component generates img in noscript tag and you will be able press space to scan the page
Because images won’t even start loading until JavaScript fully downloads and executes versus loading in parallel with other activities in the page.
Lazy loading clearly works because there are sites that manage it well. But when I hear "lazy loading" I think "Medium".

The typical experience reading a medium blog is that I can spend a minute, or a full 15 minutes, digesting the opening paragraphs. With the page idle that whole time. Then I can scroll down to a big brown smear, and read the whole caption before the associated image finishes loading.

I totally understand these images don't need to load with the first round of content. But you know I'm going to scroll down. Just use a timer or something.

Seems very interesting. I'll give it a shot and try integrating it @ SaaSHub.com. Thanks for sharing and implementing it.
You know what’s an almost ideal image component? <img>. Sure, browsers could be a little cleverer about prioritising image loading, and I wish everyone would prefer to slim their images down somewhat, but compared with all other attempts I have encountered (with no exceptions), <img> is almost ideal.

I unconditionally hate all scroll-based lazy loading of images. Any other forms of lazy loading of images such as you outline in this post I will also hate, p≥0.96. And attempts to be clever like detecting high latency and working otherwise in such situations normally mess up what I want to happen.

I’ve written about these things before and I’ll doubtless write about it again; https://news.ycombinator.com/item?id=16518010 is the last time I wrote about it on HN and some discussion arose. (The previous time was on the SVG image placeholders article linked elsewhere in these comments.)

(comment deleted)
Most of this comment is just you being dismissive about an idea without any real reason presented for being dismissive. The only useful bit here is actually in your linked comment which most people will probably not see and that is that lazy loaded images tend to fail a lot on poor internet connections. I would argue that even in that case, lazy loading images arent necessarily bad depending on the situation: imagine a site like imgur, where you will likely browse to another page without ever loading all of the images. In that case, the browser would still have loaded the image if it were an img tag and this way you get to the next page faster. Sometimes the browser will cancel the img download, but its not reliable. If the js were coded to handle errors on loading the image, that would probably be a better situation overall.
It’s much worse than just the potential for failure, as I indicate in other places I’ve written about it. If I ever see evidence that scroll-based lazy loading has occurred, it has failed in its mission: it didn’t load the image in time. And in practice, this happens a lot of the time, especially in higher latency situations. You can’t sufficiently-well predict what the user is going to do and so only load it just in time. It doesn’t work.

I am inspired by your grumbling to write a blog post entitled “Scroll-based lazy loading of images is always bad”. I won’t publish it for a while so I can treat the subject methodically (and I’m busy for the rest of today), but it will come.

Thanks for the imgur comparison; the wording I’ve used does fall down there; in my mind I had distinguished scroll-based lazy loading and scroll-based lazy loading of images. When talking about scroll-based lazy loading of images, I meant where you have content that contains images, rather than situations where the images are the content. (That is, I’m talking about lazy loading just the <img>, not lazy loading content in general.) There are definitely applications for which loading everything up-front is impossible (e.g. imgur infinite scrolling on mobile) or impractical (e.g. showing all the 10,000 messages in a mailbox in an email client that deliberately eschews pagination, like FastMail); in such situations, lazy loading is necessary and while it will often be annoying and imperfect there is and can be no better solution.

Where images are embedded in the content, however, I think that my position is still reasonable; there is an alternative: just load eagerly rather than lazily. Now articles and blog posts are the primary application I have in mind, and I can’t think of any other applications where my position would not hold—given the caveats of interpretation specified in the previous paragraph—but I’m willing to hear other suggestions.

Ok I see your use case: you load page on good connection, then connection get worse and images are not loaded when you scroll to it.

This component allows to retry image load (click on it).

It can be even more smart, like if network is good go ahead and download everything. Need to think about it

The failure case is worse than that: I may not have a connection by that time.

Even if I do have a connection and it all succeeds, if the image is not there when I scroll to it, the lazy loader has failed in its job. And that’s pretty much unavoidable in general content—people don’t always scroll smoothly through a page; I may jump down a page at a time, or skim through some headings looking at illustrations that haven’t loaded yet because they only figured I might be interested in them a bit under half a second ago, and latency is half a second plus probably another couple of tenths of a second of annoying fade-in transition. The possibilities are endless.

Come live in Australia for a bit and deliberately use sites from the US with scroll-based lazy-loading: I predict you will rapidly acquire a healthy dislike for the technique! :-)

I'll definitely take your use case into the consideration in the future
By handling failure nicely, your component seems to be better than any others I’ve heard of. (Thanks for doing that.) It’s even improving over browsers’ handling of it (right click, reload image) in situations where the intrinsic width and height of the image are not specified or overridden in CSS, which causes the <img> to collapse to generally the alt text height. (Responsiveness is often obtained with images via { max-width: 100%; height: auto }, but browsers don’t use the intrinsic width and height of the image to calculate the auto height. Hmm, I think this could be considered a bug; I might try my luck filing it against Gecko.)

But still, as a user I would consistently prefer a plain <img> to any fanciness.

I much prefer a pixelated or blurry preview image first and then the real image instead of waiting 20 years for images to load staring at a blank page. i notice the perceived speed difference on websites that do this and those that don't. Medium does it well and this react component image approach is similar. And once it is loaded, it is an <img />
Images load in the background, so the other content will be available before the images are all finished loading.

As a rule, I’d much rather see nothing or a solid colour than a pixelated or blurred preview of the image; I find it and the transition surprisingly disconcerting. I mentioned this at https://news.ycombinator.com/item?id=16516126#16558042 and have heard others agree with me.

This component supports solid color as placeholder. The same way as Google Images or Pinterest do
I've previously experimented with image loading components for fun. Similarly, I implemented the material design image loading spec for the web a few years ago.

This may come off a bit negative, but I disagree that it provides a better UX. I don't know if I've grown jaded or cynical, or if we just have drastically different preferences. I think embedding a thumbnail with a link to the full-sized image is better; it's certainly simpler. In general, I don't think the tradeoffs are worthwhile.

Some thoughts:

* There is no mention of module size. That can have a big effect on your initial pageload. Of course, this depends a lot on the context in which you are using said module. It might still be sensible for certain kinds of galleries, perhaps less so for an application for which images are of secondary concern.

* The discussion on performance is too focused on mobile and having very few images on the screen at the same time. What about desktop? What if you plan on having more than two images on-screen at the same time? Doing a comparison with traditional img tags on a grid-view gallery with 100 images would be much more interesting.

* I think it would be genuinely interesting to see what the real-world experience would be if you took a popular website and dropped this in. I do not believe that it would often be an improvement. The two sites that come to mind are 4chan and Reddit.

Module size is ~7Kb. A detailed comparison is here https://github.com/stereobooster/react-ideal-image/blob/mast...

> The discussion on performance is too focused on mobile

Because mobile users have a slower internet connection and worse CPUs.

What kind of performance are you talking about? If load performance, then this component uses well-established techniques (not invented by me), like lazy-loading (known since jQuery times), srcset (web standard), LQIP (used by Facebook, Medium), width, height (required for all blocks in AMP).

If you are talking about JS performance like frame rate or paint or "junk" on the scroll - I didn't measure it but didn't say it was the first target either.