fix(photoswipe): keyboard arrow animation via CSS keyframes
Previous approach (CSS transition + reflow trick) is unreliable in Firefox. New approach: PhotoSwipe emits 'change' synchronously before painting; we add a direction-aware CSS keyframe animation to the incoming slide element, with animation-fill-mode:both so there is no flash before the animation starts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
This commit is contained in:
@@ -459,6 +459,19 @@ body::after {
|
||||
/* iOS Safari: 100vh freezes when address bar hides; dvh tracks the live viewport */
|
||||
.pswp { height: 100dvh; }
|
||||
|
||||
/* Keyboard arrow navigation slide-in animations */
|
||||
.pswp-key-from-right { animation: pswpKeyFromRight 0.35s cubic-bezier(0.4, 0, 0.22, 1) both; }
|
||||
.pswp-key-from-left { animation: pswpKeyFromLeft 0.35s cubic-bezier(0.4, 0, 0.22, 1) both; }
|
||||
|
||||
@keyframes pswpKeyFromRight {
|
||||
from { transform: translateX(48px); opacity: 0; }
|
||||
to { transform: translateX(0); opacity: 1; }
|
||||
}
|
||||
@keyframes pswpKeyFromLeft {
|
||||
from { transform: translateX(-48px); opacity: 0; }
|
||||
to { transform: translateX(0); opacity: 1; }
|
||||
}
|
||||
|
||||
/* ── Map page ────────────────────────────────────────────────────────────────── */
|
||||
|
||||
.map-page .site-main { max-width: none; padding: 0; }
|
||||
|
||||
@@ -111,15 +111,31 @@ const lightbox = new PhotoSwipeLightbox({
|
||||
pswpModule: () => import('https://cdn.jsdelivr.net/npm/photoswipe@5/dist/photoswipe.esm.min.js')
|
||||
});
|
||||
lightbox.on('afterOpen', function () {
|
||||
var container = lightbox.pswp.element.querySelector('.pswp__container');
|
||||
var pswp = lightbox.pswp;
|
||||
var keyDir = 0;
|
||||
var clearTimer = null;
|
||||
function onKey(e) {
|
||||
if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') return;
|
||||
container.style.transition = 'transform 0.35s cubic-bezier(0.4, 0, 0.22, 1)';
|
||||
container.getBoundingClientRect();
|
||||
setTimeout(function () { container.style.transition = ''; }, 400);
|
||||
if (e.key === 'ArrowRight') keyDir = 1;
|
||||
else if (e.key === 'ArrowLeft') keyDir = -1;
|
||||
else keyDir = 0;
|
||||
}
|
||||
document.addEventListener('keydown', onKey, true);
|
||||
lightbox.pswp.on('close', function () { document.removeEventListener('keydown', onKey, true); });
|
||||
pswp.on('change', function () {
|
||||
if (!keyDir) return;
|
||||
var dir = keyDir;
|
||||
keyDir = 0;
|
||||
var el = pswp.currSlide && pswp.currSlide.el;
|
||||
if (!el) return;
|
||||
el.classList.remove('pswp-key-from-left', 'pswp-key-from-right');
|
||||
el.offsetWidth;
|
||||
el.classList.add(dir > 0 ? 'pswp-key-from-right' : 'pswp-key-from-left');
|
||||
clearTimeout(clearTimer);
|
||||
clearTimer = setTimeout(function () { el.classList.remove('pswp-key-from-left', 'pswp-key-from-right'); }, 400);
|
||||
});
|
||||
pswp.on('close', function () {
|
||||
document.removeEventListener('keydown', onKey, true);
|
||||
clearTimeout(clearTimer);
|
||||
});
|
||||
});
|
||||
lightbox.init();
|
||||
|
||||
|
||||
@@ -146,15 +146,31 @@ const lightbox = new PhotoSwipeLightbox({
|
||||
pswpModule: () => import('https://cdn.jsdelivr.net/npm/photoswipe@5/dist/photoswipe.esm.min.js')
|
||||
});
|
||||
lightbox.on('afterOpen', function () {
|
||||
var container = lightbox.pswp.element.querySelector('.pswp__container');
|
||||
var pswp = lightbox.pswp;
|
||||
var keyDir = 0;
|
||||
var clearTimer = null;
|
||||
function onKey(e) {
|
||||
if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') return;
|
||||
container.style.transition = 'transform 0.35s cubic-bezier(0.4, 0, 0.22, 1)';
|
||||
container.getBoundingClientRect();
|
||||
setTimeout(function () { container.style.transition = ''; }, 400);
|
||||
if (e.key === 'ArrowRight') keyDir = 1;
|
||||
else if (e.key === 'ArrowLeft') keyDir = -1;
|
||||
else keyDir = 0;
|
||||
}
|
||||
document.addEventListener('keydown', onKey, true);
|
||||
lightbox.pswp.on('close', function () { document.removeEventListener('keydown', onKey, true); });
|
||||
pswp.on('change', function () {
|
||||
if (!keyDir) return;
|
||||
var dir = keyDir;
|
||||
keyDir = 0;
|
||||
var el = pswp.currSlide && pswp.currSlide.el;
|
||||
if (!el) return;
|
||||
el.classList.remove('pswp-key-from-left', 'pswp-key-from-right');
|
||||
el.offsetWidth;
|
||||
el.classList.add(dir > 0 ? 'pswp-key-from-right' : 'pswp-key-from-left');
|
||||
clearTimeout(clearTimer);
|
||||
clearTimer = setTimeout(function () { el.classList.remove('pswp-key-from-left', 'pswp-key-from-right'); }, 400);
|
||||
});
|
||||
pswp.on('close', function () {
|
||||
document.removeEventListener('keydown', onKey, true);
|
||||
clearTimeout(clearTimer);
|
||||
});
|
||||
});
|
||||
lightbox.init();
|
||||
|
||||
|
||||
@@ -515,15 +515,31 @@ const lightbox = new PhotoSwipeLightbox({
|
||||
pswpModule: () => import('https://cdn.jsdelivr.net/npm/photoswipe@5/dist/photoswipe.esm.min.js')
|
||||
});
|
||||
lightbox.on('afterOpen', function () {
|
||||
var container = lightbox.pswp.element.querySelector('.pswp__container');
|
||||
var pswp = lightbox.pswp;
|
||||
var keyDir = 0;
|
||||
var clearTimer = null;
|
||||
function onKey(e) {
|
||||
if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') return;
|
||||
container.style.transition = 'transform 0.35s cubic-bezier(0.4, 0, 0.22, 1)';
|
||||
container.getBoundingClientRect(); // force reflow so browser commits current position as "from"
|
||||
setTimeout(function () { container.style.transition = ''; }, 400);
|
||||
if (e.key === 'ArrowRight') keyDir = 1;
|
||||
else if (e.key === 'ArrowLeft') keyDir = -1;
|
||||
else keyDir = 0;
|
||||
}
|
||||
document.addEventListener('keydown', onKey, true);
|
||||
lightbox.pswp.on('close', function () { document.removeEventListener('keydown', onKey, true); });
|
||||
pswp.on('change', function () {
|
||||
if (!keyDir) return;
|
||||
var dir = keyDir;
|
||||
keyDir = 0;
|
||||
var el = pswp.currSlide && pswp.currSlide.el;
|
||||
if (!el) return;
|
||||
el.classList.remove('pswp-key-from-left', 'pswp-key-from-right');
|
||||
el.offsetWidth; // restart animation if navigating rapidly
|
||||
el.classList.add(dir > 0 ? 'pswp-key-from-right' : 'pswp-key-from-left');
|
||||
clearTimeout(clearTimer);
|
||||
clearTimer = setTimeout(function () { el.classList.remove('pswp-key-from-left', 'pswp-key-from-right'); }, 400);
|
||||
});
|
||||
pswp.on('close', function () {
|
||||
document.removeEventListener('keydown', onKey, true);
|
||||
clearTimeout(clearTimer);
|
||||
});
|
||||
});
|
||||
lightbox.init();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user