My personal photography website
steve.phot
portfolio
photography
svelte
sveltekit
1<script lang="ts">
2 let {
3 src,
4 thumb,
5 alt,
6 class: className = "",
7 }: {
8 src: string;
9 thumb: string;
10 alt: string;
11 class?: string;
12 } = $props();
13
14 let loaded = $state(false);
15 let thumbAspect = $state(0);
16 let thumbImg: HTMLImageElement;
17
18 function onThumbLoad() {
19 if (thumbImg.naturalWidth && thumbImg.naturalHeight) {
20 thumbAspect = thumbImg.naturalWidth / thumbImg.naturalHeight;
21 }
22 }
23
24 $effect(() => {
25 loaded = false;
26 const img = new Image();
27 img.onload = () => {
28 loaded = true;
29 };
30 img.src = src;
31
32 return () => {
33 img.onload = null;
34 };
35 });
36</script>
37
38<div
39 class="progressive-container"
40 style="max-width: 4000px; {thumbAspect ? `aspect-ratio: ${thumbAspect};` : ''}"
41>
42 <img
43 bind:this={thumbImg}
44 src={loaded ? src : thumb}
45 {alt}
46 class="{className} progressive-image"
47 class:progressive-loading={!loaded}
48 onload={onThumbLoad}
49 />
50</div>
51
52<style>
53 .progressive-container {
54 width: 100%;
55 }
56
57 .progressive-container .progressive-image {
58 width: 100%;
59 height: 100%;
60 object-fit: contain;
61 }
62
63 .progressive-image {
64 transition: filter 0.6s ease-out;
65 }
66
67 .progressive-loading {
68 filter: blur(20px);
69 }
70</style>