global : reveal images only once fully loaded, prevent printer effect. related to #55
All checks were successful
Deploy / Deploy to Production (push) Successful in 5m25s
All checks were successful
Deploy / Deploy to Production (push) Successful in 5m25s
Images start at opacity:0 and fade in on load event. MutationObserver catches cached images before first paint to show them instantly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e2939da0ee
commit
701c5d1f56
1 changed files with 33 additions and 0 deletions
|
|
@ -117,6 +117,31 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
// --- Global image reveal: hide until loaded, then fade in ---
|
||||||
|
const onImgLoad = (e) => {
|
||||||
|
if (e.target.tagName === 'IMG') e.target.classList.add('loaded')
|
||||||
|
}
|
||||||
|
document.addEventListener('load', onImgLoad, true)
|
||||||
|
|
||||||
|
// MutationObserver: catch cached images before first paint
|
||||||
|
const imgObserver = new MutationObserver((mutations) => {
|
||||||
|
for (const m of mutations) {
|
||||||
|
for (const node of m.addedNodes) {
|
||||||
|
if (node.nodeType !== 1) continue
|
||||||
|
const imgs = node.tagName === 'IMG' ? [node] : node.querySelectorAll?.('img') ?? []
|
||||||
|
for (const img of imgs) {
|
||||||
|
if (img.complete && img.naturalWidth > 0) img.classList.add('loaded')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
imgObserver.observe(document.body, { childList: true, subtree: true })
|
||||||
|
|
||||||
|
// Already-present images
|
||||||
|
document.querySelectorAll('img').forEach(img => {
|
||||||
|
if (img.complete && img.naturalWidth > 0) img.classList.add('loaded')
|
||||||
|
})
|
||||||
|
|
||||||
const handleResize = () => {
|
const handleResize = () => {
|
||||||
isResizing = true
|
isResizing = true
|
||||||
clearTimeout(resizeTimer)
|
clearTimeout(resizeTimer)
|
||||||
|
|
@ -181,6 +206,8 @@
|
||||||
window.addEventListener('touchend', handleTouchEnd, { passive: true })
|
window.addEventListener('touchend', handleTouchEnd, { passive: true })
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
document.removeEventListener('load', onImgLoad, true)
|
||||||
|
imgObserver.disconnect()
|
||||||
window.removeEventListener('resize', handleResize)
|
window.removeEventListener('resize', handleResize)
|
||||||
window.removeEventListener('keydown', handleKeydown)
|
window.removeEventListener('keydown', handleKeydown)
|
||||||
window.removeEventListener('touchstart', handleTouchStart)
|
window.removeEventListener('touchstart', handleTouchStart)
|
||||||
|
|
@ -255,6 +282,12 @@
|
||||||
:global(img) {
|
:global(img) {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(img.loaded) {
|
||||||
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue