470 points by ChiptuneIsCool 3 months ago | 75 comments
esprehn 3 months ago
My one feedback would be to avoid using attr selectors on the style attribute like [style*="--lqip:"]. Browsers normally lazy compute that string version of the style attribute [1], but if you use a selector like this then on every style recalc it'll force all new inline styles (ex. element.style.foo = bar) to compute the string version.
Instead if you use a separate boolean attribute (or even faster a class) it'll avoid that perf foot gun. So write <div lqip style="--lqip: ..."> and match on that.
[1] https://source.chromium.org/chromium/chromium/src/+/main:thi...
cAtte_ 3 months ago
<img src="…" lqip="192900">
cendyne 3 months ago
miragecraft 3 months ago
WorldMaker 3 months ago
matthberg 3 months ago
I'm also curious to see that they're doing solely grayscale radial gradients over the base color instead of tweaking the base color's `L` value and using that as the radial gradient's center, I'd imagine you'd be doing more math that way in the OKLab colorspace which might give prettier results(?).
Tempted to play around with this myself, it's a really creative idea with a lot of potential. Maybe even try moving the centers (picking from a list of pre-defined options with the two bits stolen from the base color's L channel), to account for varying patterns (person portraits, quadrant-based compositions, etc).
mubou 3 months ago
I wonder what other things could be encoded this way. Those generic profile pictures, perhaps? (The ones where your email or account id is hashed to produce some unique geometric pattern.)
mattdesl 3 months ago
Something to note is that Color Theif (Quantize) is using median cut on RGB, it would be interesting to try and extract dominant color in OKLab instead.
I also love the idea of a genetic algorithm to find an ideal match for a given image; it should be possible to simulate radial gradients server & client side with webgpu, but probably overkill for such a simple task.
EDIT: Although it works for me in Chrome, it doesn't seem to work in Safari v16.1.
emsixteen 3 months ago
diiiimaaaa 3 months ago
It's not clear if these placeholders do actually help, especially placeholders with very low quality. In my opinion, they only add visual noise.
I'd focus more on avoiding layout shifts when images load, and serving images in a good format (avif, webp) and size (use `srcset` or `<picture>`).
biker142541 3 months ago
Well, it depends what you mean by help. It’s very dependent on use case and desired UX. Obviously you can prevent layout shifts without them, you can provide feedback on loading status in other ways, and ensure images don’t slow load time without colored placeholders. But they can provide a pleasant UX for some use cases, when done right. They can be annoying when not done well.
WorldMaker 3 months ago
When the CRDT or document sync engine inevitably sync much faster than your blobs you have something to show in that placeholder. If the blob sync fails for some reason, you still have something to show more interesting than your browser’s old broken image logo under your “Sync is slow or broken” warning.
I think placeholders help a bunch in situations like that where your image fetch is a lot more complicated than a URL that you can add in a `src` attribute. It’s also really easy to get into situations where such blob fetching is complex: In cases where you have to respect user and/or tenant privacy and need complex OAuth flows. In cases where you need end-to-end photo encryption. In cases where you need peer-to-peer sync and only P2P sync because you’ve been mandated to reduce touch points and likelihood of accidentally storing photos at rest in middle layers. Situations like images of HIPAA data, PII, PIFI, etc.
On a static site with public (or cookie sessioned) images direct linked by URL, yeah the placeholders don’t do much other than check certain design boxes. There’s lots of other places images (and their metadata) come from, and placeholders are a useful fallback in the worst cases.
JimDabell 3 months ago
simonw 3 months ago
throwaway2016a 3 months ago
Definitely very low resolution, but compared to sites that use a solid color this seems much better. And only requiring one variable is really nice.
The article seems very well thought through. Though for both the algorithm and the benchmark algorithm the half blue / half green image with the lake shows the limitations of this technique. Still pretty good considering how light weight it is.
8n4vidtmkvmk 3 months ago
In fact, LQIP looks better than most of the BlurHash examples in the gallery (https://leanrada.com/notes/css-only-lqip/gallery/); not sure if these were cherry picked or what.
Kalabasa 3 months ago
I did deliberately pick some "bad" examples like the blue+green image, and other multicolor images.
I wanted to add an upload function so people could test any image, then i realised I'd have to implement the compression/hashing in the client. Maybe i should!
simonw 3 months ago
Here's the transcript and code: https://claude.ai/share/4a562082-b681-4f0c-909c-3c32c34fd050
throwaway2016a 3 months ago
Great work!
Cieric 3 months ago
chmod775 3 months ago
bufferoverflow 3 months ago
Lord_Zero 3 months ago
bufferoverflow 3 months ago
Lord_Zero 3 months ago
https://www.npmjs.com/package/@squoosh/cli#project-no-longer...
So to clarify, is the GitHub maintained but the npm distribution is not? Or is none of it maintained unless you use the website/app?
ssttoo 3 months ago
background: linear-gradient(
to right,
#51463e 0%,
#28241f 100%
);
Tool: https://tools.w3clubs.com/gip/dmitrygr 3 months ago
Maybe we should have kept CSS simple and JS optional. Maybe we took a few wrong turns...
cjpearson 3 months ago
duffyjp 3 months ago
I still do the average color thing today since it's easy to calculate and store server side (I resize the uploaded image to 1x1 px and just record the result as a hex code in the DB).
biker142541 3 months ago
cynicalsecurity 3 months ago
simonw 3 months ago
Kalabasa 3 months ago
Hackbraten 3 months ago
layer8 3 months ago
mike2323 3 months ago
thangngoc89 3 months ago
Safari 18.0 (20619.1.26.31.6), macOS Sequoia 15.0
tlb 3 months ago
Safari 17.6 (19618.3.11.11.5), MacOS Sonoma 14.7.3 (23H417)
It works on Chrome on the same machine.
alwillis 3 months ago
simonw 3 months ago
VladVladikoff 3 months ago
whstl 3 months ago
wruza 3 months ago
Reubend 3 months ago
bmandale 3 months ago
turnsout 3 months ago
WorldMaker 3 months ago
Zensynthium 3 months ago
thwarted 3 months ago
molszanski 3 months ago
davidmurdoch 3 months ago
jbverschoor 3 months ago
seejayseesjays 3 months ago
superkuh 3 months ago
So a CSS-only way is neat and indisputably better but I think it's missing the point? The point of blurry placeholders isn't to make things easier or display better. The point is to make things worse. This write up is definitely making things better.
simonw 3 months ago
I'm not sure why you think it has anything to do with forcing people to execute JavaScript?
wruza 3 months ago
simonw 3 months ago
gblargg 3 months ago
jasonkester 3 months ago
simonw 3 months ago
nirava 3 months ago
My goal was to have something that'd transmit all the essential bits of the site in the first 14kB, and worked basically on everything. It wasn't hard, honestly.
It wasn't a particularly complex site but i guess what I'm saying is any well done (and well intentioned) implementation of blurred image placeholders will works with or without JS. That is just sound engineering...
recursive 3 months ago
superkuh 3 months ago
recursive 3 months ago
naveed125 3 months ago
csdn1111 3 months ago
benfortuna 3 months ago
jsheard 3 months ago
ipunchghosts 3 months ago
teraflop 3 months ago
One of the many ways CSS allows you to customize formatting is to change the background style of elements. In addition to just using a solid color or image, you can specify a procedural gradient. And by superimposing several such gradients, you can make a very blurry approximation of an image.
CSS also includes a basic expression language which allows evaluating simple arithmetic expressions. So you can encode all the blurred image's parameters as a packed integer in a single compact CSS property per image, and use rules to define the gradients in terms of that integer.
Note that CSS is not used to compute the blurred image representation itself -- you have to do that separately. (Even if you could do it in pure CSS, the whole point is to show a blurred preview image before the image itself is downloaded to the browser, so doing it in CSS would defeat the purpose.)
maxbond 3 months ago
A more accurate mental model might be, "a declarative language for styling HTML elements," where "styling" is very broad. You can make user interfaces that show and hide elements, have animations, etc. triggered by clicking buttons without a single line of JavaScript. It's a lot more powerful than the configuration parameters to plotting functions, in my book it's a programming language rather than a configuration language.
rckt 3 months ago
Also a bit of nitpicking. While it provides a visual placeholder for an image that's being fetched, it does not reflect its content. So, when it's loaded we can see a completely different color palette and shapes.
tempoponet 3 months ago
First is the limitation to one hue value. Something like the Sunflower (blue + yellow) is just yellow. Maybe there's a tradeoff that could pack more hue but with less luminescence.
The second is how the primary color is selected. Several images (plant on grey background, street food vendor) appear to be averaging across the image and getting a grey value. By selecting better for the predominant color and its placement, the greys would appear on their own.
pavlov 3 months ago
You don’t even need JavaScript to decode that integer into the image. The underlying CSS may be complex, but for the user of the library it definitely feels minimal in a good way.
rckt 3 months ago
As for the minimalism, I understand what you mean. But I understood the "minimal" part in regard to implementation, not usage. If we only mean usage, we can say the same about a lot of libs, that they are minimal. Yeah, it's minimal for the end user, but under the hood it is not as minimal. It's not anything bad, it's just how I interpreted the title.
mary-ext 3 months ago