Fix slideshow crossfade flash — wait for image load before fading in

Previously the active class was applied via requestAnimationFrame
before the image had decoded, causing a brief blank-then-flash.
Now loadSlide waits for onload before transitioning, and advanceSlide
checks complete/naturalWidth (or waits for onload) on the preloaded
slot before doing the swap.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-28 21:41:25 +12:00
parent afddfd5bb1
commit 1e97e7c805

View File

@@ -302,10 +302,17 @@ function hideSlideshow() {
function loadSlide(slot, url) { function loadSlide(slot, url) {
const img = document.getElementById(`slide-${slot}`); const img = document.getElementById(`slide-${slot}`);
img.src = url;
if (slot === activeSlot) { if (slot === activeSlot) {
// Slight delay lets the browser decode before fading in // Only fade in once the image is fully decoded — no blank-then-flash
requestAnimationFrame(() => requestAnimationFrame(() => img.classList.add('active'))); img.onload = () => { img.onload = null; img.classList.add('active'); };
img.src = url;
// Handle cached images that won't fire onload
if (img.complete && img.naturalWidth > 0) {
img.onload = null;
img.classList.add('active');
}
} else {
img.src = url; // preload only
} }
} }
@@ -314,13 +321,20 @@ function advanceSlide() {
const current = document.getElementById(`slide-${activeSlot}`); const current = document.getElementById(`slide-${activeSlot}`);
const next = document.getElementById(`slide-${nextSlot}`); const next = document.getElementById(`slide-${nextSlot}`);
// Fade in the preloaded next image, fade out current const doSwap = () => {
next.classList.add('active'); next.onload = null;
current.classList.remove('active'); next.classList.add('active');
activeSlot = nextSlot; current.classList.remove('active');
activeSlot = nextSlot;
// Preload the upcoming photo into the now-hidden slot
slideIndex = (slideIndex + 1) % photos.length;
current.src = photos[(slideIndex + 1) % photos.length];
};
// Preload the one after next into the now-hidden slot // If the preloaded image is ready, swap immediately; otherwise wait for it
slideIndex = (slideIndex + 1) % photos.length; if (next.complete && next.naturalWidth > 0) {
const upcoming = photos[(slideIndex + 1) % photos.length]; doSwap();
current.src = upcoming; } else {
next.onload = doSwap;
}
} }