H11Y BLOG Logo

Svelte Progressive Image Loader with Cloudinary

5/25/2023

Made this old blog called Faireoui a long time ago. Just want to add this here.

It had cool images that blurred in. So I thought I would recreate that here.

Example

water
A photo I took while on the transom of a catamaran in the BVIs. Rendered with an H11YImage component.

The code for the image tag is relatively easy to implement and I was greatly helped by Easy “Blur Up” Image Loading with React Hook by Ben Honeywill. Thanks Ben.

Implementation of custom image component

Simply upload an image to Cloudinary and identify the image name and the cloud name.

<script>
	import { H11YImage } from 'h11y-scl';
	const cloudinaryCloudName = 'dd1sqkcyf';
	const cloudinaryImageName = 'water_gqyt9r';
	const imageAlt = 'Picture of water';
</script>

<H11YImage cloudName={cloudinaryCloudName} imageName={cloudinaryImageName} alt="water" />

The Cloudinary Image Wrapper

This H11YImage component generates the low res and “high” res image urls.

<script lang="ts">
	import { Cloudinary } from '@cloudinary/url-gen';
	import { Resize } from '@cloudinary/url-gen/actions/resize';
	import { Effect } from '@cloudinary/url-gen/actions/effect';
	import Image from './Image.svelte';

	export let cloudName: string;
	export let alt: string;
	export let imageName: string;

	const cld = new Cloudinary({
		cloud: {
			cloudName
		}
	});

	const myImage = cld.image(imageName);
	myImage.resize(Resize.scale().width('800'));
	const srcURL = myImage.toURL();
	myImage.effect(Effect.vectorize());
	const loadingURL = myImage.toURL();
</script>

<Image lowResUrl={loadingURL} highResUrl={srcURL} {alt} />

The Base Image Component

This component will load a low resolution image first and then replace it with the higher resolution image which will lead to faster load times.

<script lang="ts">
	import { writable } from 'svelte/store';
	export let lowResUrl: string;
	export let highResUrl: string;
	export let alt: string;

	const srcUrl = writable(lowResUrl);

	function onLoad() {
		if (highResUrl !== $srcUrl) {
			srcUrl.set(highResUrl);
		}
	}
</script>

<img src={$srcUrl} {alt} loading="lazy" on:load={onLoad} class:blurred={$srcUrl !== highResUrl} />

<style lang="postcss">
	img {
		background-position: center;
		background-repeat: no-repeat;
		background-size: cover;
		filter: none;
		transition: filter 0.8s ease-out;
	}
	.blurred {
		filter: blur(10px);
		transition: none;
	}
</style>