gallery animation : reveal only once all images are loaded. related to #55
All checks were successful
Deploy / Deploy to Production (push) Successful in 21s
All checks were successful
Deploy / Deploy to Production (push) Successful in 21s
Preload unique image URLs via new Image(). Container stays at opacity:0 until all are ready, then reveals at once. Cached images show instantly (no fade transition). Fixes broken progressive reveal in scrolling gallery. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9d7fca4d91
commit
cc61a83139
1 changed files with 37 additions and 0 deletions
|
|
@ -7,8 +7,35 @@
|
||||||
* @prop {number} secondsPerImage — durée par image (défaut: 8s)
|
* @prop {number} secondsPerImage — durée par image (défaut: 8s)
|
||||||
* @prop {'vertical'|'horizontal'} mode — direction du défilement
|
* @prop {'vertical'|'horizontal'} mode — direction du défilement
|
||||||
*/
|
*/
|
||||||
|
import { onMount } from 'svelte'
|
||||||
|
|
||||||
let { images = [], secondsPerImage = 8, backgroundColor = null, backgroundImage = null, mode = 'vertical' } = $props()
|
let { images = [], secondsPerImage = 8, backgroundColor = null, backgroundImage = null, mode = 'vertical' } = $props()
|
||||||
|
|
||||||
|
let containerEl = $state(null)
|
||||||
|
let allLoaded = $state(false)
|
||||||
|
let needsFade = $state(false)
|
||||||
|
|
||||||
|
// Wait for all unique source images to load before revealing
|
||||||
|
onMount(() => {
|
||||||
|
const uniqueSrcs = new Set(images.map(img => img.src).filter(Boolean))
|
||||||
|
if (uniqueSrcs.size === 0) { allLoaded = true; return }
|
||||||
|
|
||||||
|
let remaining = uniqueSrcs.size
|
||||||
|
const done = () => { if (--remaining <= 0) allLoaded = true }
|
||||||
|
|
||||||
|
for (const src of uniqueSrcs) {
|
||||||
|
const img = new Image()
|
||||||
|
img.src = src
|
||||||
|
if (img.complete) {
|
||||||
|
done()
|
||||||
|
} else {
|
||||||
|
needsFade = true
|
||||||
|
img.onload = done
|
||||||
|
img.onerror = done
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const columns = $derived.by(() => {
|
const columns = $derived.by(() => {
|
||||||
const count = images.length
|
const count = images.length
|
||||||
const duration = count * secondsPerImage
|
const duration = count * secondsPerImage
|
||||||
|
|
@ -40,6 +67,8 @@
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="gallery-animation gallery-animation--{mode}"
|
class="gallery-animation gallery-animation--{mode}"
|
||||||
|
class:gallery-animation--ready={allLoaded}
|
||||||
|
class:gallery-animation--fade={needsFade}
|
||||||
style="--gallery-duration: {columns[0]?.duration ?? 24}s{backgroundColor ? `; --background-color: ${backgroundColor}` : ''}{backgroundImage ? `; --gallery-background-image: url(${backgroundImage})` : ''}"
|
style="--gallery-duration: {columns[0]?.duration ?? 24}s{backgroundColor ? `; --background-color: ${backgroundColor}` : ''}{backgroundImage ? `; --gallery-background-image: url(${backgroundImage})` : ''}"
|
||||||
>
|
>
|
||||||
<div class="gallery-animation__overlay"></div>
|
<div class="gallery-animation__overlay"></div>
|
||||||
|
|
@ -80,9 +109,17 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background-color: var(--background-color, transparent);
|
background-color: var(--background-color, transparent);
|
||||||
background-image: var(--gallery-background-image);
|
background-image: var(--gallery-background-image);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-animation--ready {
|
||||||
opacity: .8;
|
opacity: .8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gallery-animation--fade.gallery-animation--ready {
|
||||||
|
transition: opacity 0.4s ease;
|
||||||
|
}
|
||||||
|
|
||||||
.gallery-animation__overlay {
|
.gallery-animation__overlay {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue