svimg
svimg copied to clipboard
Image blurred when already loaded
When an image is loaded, it is normal that a blurring occurs. However, when it's already loaded, it should not be blurred and wait for the onload
event.
Demo: https://www.escaladelaurentides.ca/
Steps to reproduce.
- Visit the main page. The blurred->sharp effect happens. That is normal.
- visit any other page (for example documents) and switch back to the main page.
Expected: The blur effect doesn't happen a second time, since the image is already loaded.
I am very impressed with the quality of this preprocessor! It's so good that I believe it should be among the default preprocessors in svelte-preprocess!
Glad it's working for you!
I'll take a look at what I can do about this, but from what I recall, it can be pretty difficult to reliably tell in Javascript whether an image is already cached by the browser. Depending on the Cache-Control headers, it might never be cached at all.
For what it's worth, for your particular example image, it might be worth using the immediate
attribute to not actually go through the lazy load at all (you can still take advantage of the image preprocessing, obviously). The biggest benefit of lazy loading is to avoid downloading non-critical offscreen images until the user scrolls the image into the viewport to improve the initial page load, but in your case, your image is pretty much always going to be in the viewport when the page first loads. Having the browser lazy-load an immediately-visible image can actually be slower due to the deferral of the image download and the browser having to make the determination of the image's visibility in the viewport, so it can actually feel less responsive.
Wow thanks for the detailed explanation!
It indeed seems that immediate
is what I need. I liked the blur effect when it ocurred only once though;)
Even though it doesn't stop anything from working, I also get this typescript error in vscode:
Have you ever encountered it?
It indeed seems that
immediate
is what I need.
Hmm there is now a flash of unstyled text (the alt text) the first time... First render looks better with only an img
tag.
I'll have a look at it.
The typescript error is something I know about - Svelte got better Typescript support sometime after I created this package, so I need to create Typescript definitions for the component now that Svelte supports that.
I think the flash is due to setting the alt text immediately, before the image has finished loading. I can probably make it a bit less jarring by deferring setting the alt text until after the image finishes loading or if the load fails. I believe that's what normal img tags do (doesn't render the alt text while the image is still loading).
I can probably make it a bit less jarring by deferring setting the alt text until after the image finishes loading or if the load fails
That sounds good
I need to create Typescript definitions for the component now that Svelte supports that.
Do you need any help with the migration to the newer system? I remember seeing somewhere that sveltekit was also a component bundler. I don't know if it's worth setting it up for a single component.
Sure, I'd be happy to look at a pull request if you put one together.
Great, I'm currently building such a monorepo. It shouldn't be too hard to make a clone of it with your preprocessor and components instead of mine. I'll tell you when I have time to tackle it.
Sorry I never came back! I just saw you updated the repo to 2.0 back in march. I just updated and the typescript error is now gone.
The double blurring still appears though, but I got used to it, and it even feels nice now:)
I don't quite understand the intended functioning of the lazy loading. When I visit https://www.escaladelaurentides.ca/ it loads all images from over the network even if they're below the page fold.
I wonder if it might be nice to rename it to loading
to match the browser and invert is so that the default is that it isn't lazy.
I just set this up on the SvelteKit demo app and it's kind of a weird experience for a couple reasons:
- the blurring seems to occur only on three edges, but not the top edge
- the image is immediately available both because it's loaded from localhost and because it's cached, but takes quite awhile to fade in
I like the ability to lazy load, but it seems like more of a special case and not necessarily something you'd want to use on every image. I don't think I'm familiar with any large content sites that have this behavior. It seems like something to use sparingly for an e-commerce results page or photo app or something where you'd only want it on the dynamically loaded content images, but not on the static images like the logo, etc.
It's using native browser image lazy loading, so the heuristics are up to the browser. The browser will often preload lazy images that are just offscreen under the expectation that the user is likely to start scrolling, to hopefully finish loading the image before the user scrolls the image into view. In this particular example, the page is short with images both immediately visible as well as just offscreen and likely preemptively loaded. Lazy loading would be more beneficial for a longer page. I think I suggested disabling lazy loading in my first comment in this issue.
Fair to consider whether the default should be lazy loading or not. This was originally created as a drop-in replacement for svelte-image
, which also lazy-loaded by default, and my original use case was a photo blog, so I kept compatibility. Lazy loading should be used with judgement and not broadly used on every image. I could at least make this clearer in the documentation. I'd imagine changing the default would need to wait until a major version break.
This issue was left open to try to find a way to disable the transition animation for content that's already loaded and cached to make it load faster as you say. I have ideas to try but haven't gotten to it yet.
Thanks for sharing the details around this! I actually didn't realize that the browser had introduced support for lazy loading. Does the fade in animation also come from the browser or is that provided by the library?
I tried to do some research on best practices around this today. I didn't find a whole lot, but I did see that the Chrome team recommends not lazily loading images are in the first visible viewport.
The blurred placeholder and the fade in animation are coming from svimg. Without it, the browser does what it usually does when it loads images (just lazily) - the document reflows when the image is loaded and suddenly has dimensions, or if you have pre-set dimensions you get a blank space until the image loads in. So the blurred placeholder is trying to fill those dimensions to avoid the reflow and provide something other than an empty box, and the fade in (CSS transition) is trying to make it less jarring when the image does actually load in (otherwise it would immediately snap into focus).
I do think I need to update the documentation with more guidance and/or links to references such as that for when to use lazy loading or not. Even if I switched the default, someone stumbling upon the lazy option without that context could still just put that option on all images and we'd be back in the same spot.