In an in-depth analysis on how Medium loads up their images, José M. Pérez explains how their “blur-up technique” works:
- Display a resized version of the original at the original size, with a blur filter on top to hide the artifacts.
- Load in the bigger one.
- Once the big version is loaded, replace the small image with the big one.
Now, at Medium they don’t just swap out the small image for the big one, but animate between the two. For this they render everything on a
<canvas> element. The author of the post has recreated the animation using CSS filters:
In a follow-up post on using SVGs as placeholders he researches how SVGs can be used as placeholders.
Now I must say his self-made results aren’t that satisfying … the jump between the lo-res SVG and the original is too big. What caught my eye in said article however, is the mention of SQIP which yields some very – very – nice results:
It makes use of Primitive to generate a SVG consisting of several simple shapes that approximate the main features visible inside the image, optimizes the SVG using SVGO and adds a Gaussian Blur filter to it. This produces a SVG placeholder which weighs in at only ~800–1000 bytes, looks smooth on all screens and provides an visual cue of image contents to come.
# Generate a SVG placeholder and print an example <img> tag to stdout
# Save the placeholder SVG to a file instead of printing the <img> to stdout
sqip -o output.svg input.jpg
# Customize the number of primitive SVG shapes (default=8) to influence bytesize or level of detail
sqip -n 4 input.jpg
There’s also a Node implementation available.
UPDATE 2017.12.03: There’s an article available over at perfplanet on how to combine SQIP with the Intersection Observer.