Closed benjivm closed 1 day ago
I have the same issue (mostly in Firefox but I think I saw it a few times in Chrome as well).
Having the same issue. It does not always scroll to top when navigating. Specially when further down the page. Very odd. Maybe its more likely firefox bug rather then inertia?
Inertia's popstate listener (popstate being the event called when the back button is used) will asynchronously load the previous component, rendering it when it has loaded. https://github.com/inertiajs/inertia/blob/f34f373692a964933e4272fc49fa48552301e568/packages/core/src/router.ts#L480-L492
The problem arises in that the browser wants to restore the previous scroll position as soon as the popstate listener exits, when the url changes, and at that point in time, the previous component has not loaded yet. So what you might be seeing is your pre-back page getting scrolled down (by browser native restoration) but hitting the bottom of the scroll bar, after which point the previous component gets rendered, just at the scroll position you managed to get to from the previous page.
I looked for an elegant solution around this issue, but failing to find one, made one that at least looks good from an end-user's perspective. It's for Vue+Typescript, but could be adapted for other environments. You would want to run this only once, probably in a global layout or something.
import { onMounted, onUnmounted } from 'vue';
import { debounce } from 'lodash-es';
import { router } from '@inertiajs/vue3';
/**
* Restores the window scroll position when navigating back to a page.
*
* The 'popstate' event handler in inertia loads the component from the previous
* page asynchronously, so browser-native scroll restoration is triggered before
* the new component is mounted, resulting in the scrollbar banging against the
* bottom of the window in the case that the page before navigating back is
* smaller in height than the scroll position to be restored. This composable
* separately tracks the window scroll position, saves it in the history state
* and restores it immediately after navigation, avoiding a flash of the
* incompletely restored scroll position.
*/
export function useWindowScrollRestoration() {
const saveWindowScroll = debounce((event: Event) => {
if (event.target === document)
router.remember(window.scrollY, 'windowScrollY');
}, 100);
function restoreWindowScroll() {
const windowScrollY = router.restore('windowScrollY');
if (typeof windowScrollY === 'number') {
window.scrollTo(0, windowScrollY);
}
}
let removeListener = () => {};
onMounted(() => {
// Disable browser-native scroll restoration
window.history.scrollRestoration = 'manual';
window.addEventListener('scroll', saveWindowScroll, true);
removeListener = router.on('navigate', restoreWindowScroll);
});
onUnmounted(() => {
window.history.scrollRestoration = 'auto';
window.removeEventListener('scroll', saveWindowScroll, true);
removeListener();
});
}
@benjivm @Hasan-Mir @ivalkenburg @fritz-c please test if #1980 fixes this issue for you.
@pedroborges I installed using npm install inertiajs/inertia#master
, will this get me the correct changes for testing?
I still see the issue in the repro repo: https://github.com/benjivm/inertiajs-firefox-scroll-position
@benjivm it's not trivial because Inertia.js uses a monorepo, here's how I did it on one of my projects:
npm i -D https://gitpkg.now.sh/inertiajs/inertia/packages/core?master
cd node_modules/@inertiajs/core
npm i
npm run build
rm -rf node_modules
npm i -D https://gitpkg.now.sh/inertiajs/inertia/packages/svelte?master
cd node_modules/@inertiajs/svelte
npm i
npm run build
rm -rf node_modules
v1.3 will be tagged next week 🤞
I'm using Vue and so changed the 2nd group of commands to the Vue3 package, and unfortunately still see the issue.
@benjivm I am also using vue3. After trying for a while I found I probably needed to go the long way around, through the contribution guide and clone it, then setup a playground for my app. I took a noob-shot at setting up through a basic package.json change could not get it.
I could not get anchor links to work AND consistent scroll position on back/forward navigation. The anchor link problem was fixed by removing smooth scrolling.
EXAMPLE: If I click an anchor link to another page on my basic lead generation site:
<Link :href="file.href" class="w-full relative"> ... Link to other page and section ... </Link>
I am automatically scrolled to the element (so long as I do not use smooth scrolling). If I use smooth scrolling it scrolls to the wrong location (ok, fine, not a big deal) . But if I press back in either case, the correct page loads at the incorrect scroll position. The position is usually lower than expected.
Here's an example of what I am talking about: https://youtu.be/rfQxhHv5Szs
I will check back at the new release to see if this fixes it. I'm nearing the end of a project so I'd rather not share the repo right now, hope that's ok.
Here's my current versions though:
npm (relevant dependencies and devdependencies together)
"@inertiajs/inertia": "^0.11.1",
"@inertiajs/progress": "^0.2.7",
"@inertiajs/server": "^0.1.0",
"@inertiajs/vue3": "^1.2.0",
"laravel-vite-plugin": "^1.0",
"vite": "^5.0",
"ziggy-js": "^2.3.0",
"@vitejs/plugin-vue": "^5.0.0",
composer versions
"laravel/sail": "^1.29",
"php": "^8.2",
"inertiajs/inertia-laravel": "^1.0",
"laravel/framework": "^11.0",
"laravel/jetstream": "^5.1",
"laravel/sanctum": "^4.0",
"laravel/tinker": "^2.9",
"tightenco/ziggy": "^2.3"
~@Rubrasum how did you remove smooth scrolling?~
Never mind. I got it, you disable on Firefox's preferences, right?
I can confirm that disabling smooth scrolling seems to fix the scroll restore.
Although this is not a fix per se, as this options is toggled by default on new Firefox installs, maybe it can guide to better understand how to work around it, or to report a bug to Firefox.
~@Rubrasum how did you remove smooth scrolling?~
Although this is not a fix per se, as this options is toggled by default on new Firefox installs, maybe it can guide to better understand how to work around it, or to report a bug to Firefox.
It was part of my own css. I'm using Laravel, Tailwind, and Inertia Vue3. So I have an app.css file here resources/monumental_theme/css/app.css
with these line at the top:
@tailwind base;
@tailwind components;
@tailwind utilities;
html {
scroll-behavior: smooth;
}
So do a search for "scroll-behavior: smooth" Or Tailwind's "scroll-smooth" class.
In my case, I didn't have any string "smooth" on my generated CSS. Then I remembered this Firefox's setting:
Toggling it off did the trick for me.
Lol, great another bug you found for me too then.
Instead of removing the smooth line, I should've added auto. If you specifically add auto it will override the default firefox setting. I just tested it very haphazardly and seemed to work.
html {
scroll-behavior: auto;
}
I'm out of office right now, tomorrow I'll give it a try and let you know.
thanks!
Hey @Rubrasum, that seems to fix it! Thanks a lot!
html {
scroll-behavior: auto;
}
Inertia v2.0.0-beta.1 appears to resolve this issue for me without resorting to the scroll-behavior
CSS mentioned above.
Version:
@inertiajs/vue3
version:^1.0.11
Describe the problem:
Browser/mouse button page navigation (forward/back) does not restore scroll position. Oddly, it does appear to work fine if the content is static (not served from a controller, e.g.)
Steps to reproduce:
Reproduction repo: https://github.com/benjivm/inertiajs-firefox-scroll-position
Open the page in Firefox (this issue does not affect Chrome).
Scroll down to about the middle of the page where the link and explanation are then navigate with your browser's nav buttons or mouse button.[
This polyfill makes it more reliable but is jarring to use.
This relates to this issue #1459