generated from boboko/starter
65 lines
2.2 KiB
JavaScript
65 lines
2.2 KiB
JavaScript
// Make a refresh land back where you were — accurately.
|
|||
|
|
//
|
||
|
|
// Turbo Drive is off site-wide (see app.js), so a refresh is a full browser
|
||
|
|
// load. The browser restores the scroll position early in that load — before
|
||
|
|
// the Manrope web fonts swap in and reflow the header, <h1> and result count
|
||
|
|
// above the product grid — so it settles a bit too low. We record the position
|
||
|
|
// ourselves and re-apply it once the layout has actually stopped moving.
|
||
|
|
//
|
||
|
|
// Separately: drop focus on the way out. Otherwise the browser re-focuses
|
||
|
|
// whatever filter control was active and scrolls it into view on reload, and
|
||
|
|
// that sidebar stacks below the grid on narrow screens — hence the jump to the
|
||
|
|
// bottom.
|
||
|
|
//
|
||
|
|
// The real fix for the drift is preloading the above-the-fold font weights so
|
||
|
|
// there's no reflow to chase; this keeps the restore correct until then, and
|
||
|
|
// harmless after.
|
||
|
|
|
||
|
|
const key = 'scrollY:' + location.pathname + location.search
|
||
|
|
|
||
|
|
let frame = 0
|
||
|
|
window.addEventListener(
|
||
|
|
'scroll',
|
||
|
|
() => {
|
||
|
|
if (frame) return
|
||
|
|
frame = requestAnimationFrame(() => {
|
||
|
|
frame = 0
|
||
|
|
try {
|
||
|
|
sessionStorage.setItem(key, String(Math.round(window.scrollY)))
|
||
|
|
} catch {}
|
||
|
|
})
|
||
|
|
},
|
||
|
|
{ passive: true },
|
||
|
|
)
|
||
|
|
|
||
|
|
window.addEventListener('pagehide', () => {
|
||
|
|
const el = document.activeElement
|
||
|
|
if (el && el !== document.body) el.blur()
|
||
|
|
})
|
||
|
|
|
||
|
|
// Only reloads and back/forward should resume a position; a fresh visit to the
|
||
|
|
// page starts where it naturally would.
|
||
|
|
const [nav] = performance.getEntriesByType('navigation')
|
||
|
|
if (nav && (nav.type === 'reload' || nav.type === 'back_forward')) {
|
||
|
|
let saved = null
|
||
|
|
try {
|
||
|
|
saved = sessionStorage.getItem(key)
|
||
|
|
} catch {}
|
||
|
|
|
||
|
|
if (saved !== null) {
|
||
|
|
const y = Number(saved)
|
||
|
|
const apply = () => window.scrollTo(0, y)
|
||
|
|
|
||
|
|
window.addEventListener(
|
||
|
|
'load',
|
||
|
|
() => {
|
||
|
|
apply()
|
||
|
|
// Fonts (and any late above-the-fold image) can still nudge
|
||
|
|
// layout a frame or two after load — re-apply once they settle.
|
||
|
|
document.fonts?.ready.then(() => requestAnimationFrame(apply))
|
||
|
|
},
|
||
|
|
{ once: true },
|
||
|
|
)
|
||
|
|
}
|
||
|
|
}
|