When you style a section far down a WordPress page, every reload throws you back to the top and you scroll down again to see the change. Browsers try to keep the position, but animations, lazy-loaded images and page builders often break that.
This snippet saves the scroll position when the page is left and restores it after a reload. It is safe on a live site: a normal visit or a click on a link always starts at the top as usual. It is also handy with the Scripts Organizer preview, which reloads after every save.
The snippet
(function () {
var key = 'dpcScroll:' + location.pathname + location.search;
var storage;
try {
storage = window.sessionStorage;
storage.getItem(key);
} catch (e) {
return; // Storage blocked: do nothing.
}
var nav = window.performance && performance.getEntriesByType ? performance.getEntriesByType('navigation')[0] : null;
var saved = parseInt(storage.getItem(key), 10);
storage.removeItem(key);
// Restore only after a reload, once images and fonts have loaded.
if (nav && nav.type === 'reload' && saved > 0) {
var restore = function () {
window.scrollTo(0, saved);
};
if (document.readyState === 'complete') {
restore();
} else {
window.addEventListener('load', restore, { once: true });
}
}
// Remember the position when the page is left or reloaded.
window.addEventListener('pagehide', function () {
try {
storage.setItem(key, String(Math.round(window.scrollY)));
} catch (e) {}
});
})();
Add it with Scripts Organizer
In Scripts Organizer go to Code Blocks → Add New and give the block a name. Set Trigger location to Conditions, tick Footer under Script location, set Footer Mode to Javascript, paste the code into the footer editor and publish. Set Template to All, or better to Page, Post and pick the page you are working on, so the script only loads there.
Scripts Organizer prints header and footer code with the Conditions trigger on the front end, not with Everywhere. It wraps the code in a <script> tag itself, so paste it without one.
How it works
- On
pagehide(leaving or reloading the page) the script storeswindow.scrollYinsessionStorage, under a key that includes the page path. Each page remembers its own position, and the value is gone when the tab is closed. - On the next load it reads and removes the value. It scrolls back only when the Navigation Timing type is
reload, so links and the back button behave normally. - It restores the position on the
loadevent, after images and fonts have loaded and the page has its final height. - It adds an event listener instead of overwriting
window.onbeforeunload, so other scripts that use that handler keep working.pagehidealso fires on mobile Safari, wherebeforeunloadoften does not. - If storage is blocked (some privacy modes), the script does nothing.
Customise it
- Restore on every visit, not only on reload: remove
nav.type === 'reload' &&from the condition. - Remember the position per tab across different query strings: remove
+ location.searchfrom the key.
Gotchas
- Smooth scrolling set in CSS (
scroll-behavior: smooth) makes the jump animated. Usewindow.scrollTo({ top: saved, behavior: 'instant' })if that bothers you. - Scroll-triggered animations above the restored position may not have run yet; that is a side effect of landing mid-page.
- For more scroll helpers see Add and Remove a Class on Scroll in WordPress.
In the Scripts Organizer library Import it with one click from Scripts Organizer.