fix(ui): scroll-coupled backdrop pan that works in every browser
build-and-deploy / build (push) Failing after 11m10s

CSS animation-timeline: scroll() is Chromium-only, so the backdrop didn't move
for non-Chromium browsers. Replace it with a tiny rAF-throttled scroll handler
in site.js (the existing same-origin script — CSP stays strict, no inline JS)
that drives a --bg-shift CSS var off scroll position. The board now pans
vertically in lock-step with scroll and sits still at rest, in all browsers.
This commit is contained in:
2026-06-27 21:02:46 +10:00
parent af7e0287d4
commit b7c91081b2
2 changed files with 37 additions and 39 deletions
+32
View File
@@ -55,5 +55,37 @@
io.observe(el);
});
}
// --- Scroll-coupled background pan -------------------------------------
// The Bat-Computer backdrop pans vertically in lock-step with scroll —
// moving ONLY while you scroll, still at rest. Plain scroll listener so it
// works in every browser (unlike CSS animation-timeline: scroll(), which is
// Chromium-only). rAF-throttled; sets a CSS var the transform reads.
var bgImgs = document.querySelectorAll(".site-bg__img");
if (bgImgs.length) {
var ticking = false;
function updateBg() {
ticking = false;
var doc = document.documentElement;
var max = doc.scrollHeight - window.innerHeight;
var p = max > 0 ? Math.min(1, Math.max(0, window.scrollY / max)) : 0;
// +half a range at the top → -half at the bottom: scrolling down pans
// the camera down the board. Range kept within the image's overhang so
// an edge never shows (image is 215% tall → 57.5vh spare each side).
var shift = (0.5 - p) * window.innerHeight * 0.7;
for (var i = 0; i < bgImgs.length; i++) {
bgImgs[i].style.setProperty("--bg-shift", shift.toFixed(1) + "px");
}
}
function onScroll() {
if (!ticking) {
ticking = true;
window.requestAnimationFrame(updateBg);
}
}
window.addEventListener("scroll", onScroll, { passive: true });
window.addEventListener("resize", onScroll, { passive: true });
updateBg();
}
});
})();
+5 -39
View File
@@ -372,12 +372,15 @@ svg {
top: 50%;
left: 50%;
/* Zoomed in — larger than viewport so the board reads big/immersive and the
scroll-pan has room to travel. */
scroll-pan has room to travel without ever revealing an edge. */
width: 215%;
height: 215%;
object-fit: cover;
transform: translate(-50%, -50%);
/* --bg-shift is driven by the scroll handler in site.js (scroll-coupled pan:
moves only as the page scrolls). Defaults to 0 → centred when JS is off. */
transform: translate(-50%, calc(-50% + var(--bg-shift, 0px)));
will-change: transform;
transition: transform 0.15s linear;
}
.site-bg__img--light {
display: none;
@@ -420,43 +423,6 @@ svg {
rgba(246, 248, 251, 0.82) 100%
);
}
/* BASELINE motion (works in EVERY browser, no JS): a slow, continuous top↔bottom
drift. This is the guaranteed fallback — Firefox/Safari don't support
scroll-driven animations, so without this the board would sit dead-still. */
@media (prefers-reduced-motion: no-preference) {
.site-bg__img {
animation: bgDrift 48s ease-in-out infinite alternate;
}
}
/* ENHANCEMENT: where scroll-driven animations exist (Chromium), couple the pan
to scroll position instead — overrides the timed drift on the same element. */
@supports (animation-timeline: scroll()) {
@media (prefers-reduced-motion: no-preference) {
.site-bg__img {
animation: bgPan linear both;
animation-timeline: scroll(root block);
}
}
}
/* Continuous timed drift (fallback) — gentle, alternates so it never jumps. */
@keyframes bgDrift {
from {
transform: translate(-50%, -38%);
}
to {
transform: translate(-50%, -62%);
}
}
/* Scroll-coupled monotonic top→bottom pan (Chromium): ~44% travel of the
215%-tall image, tied directly to page scroll progress. */
@keyframes bgPan {
from {
transform: translate(-50%, -28%);
}
to {
transform: translate(-50%, -72%);
}
}
@media (prefers-reduced-motion: reduce) {
.scroll-progress {