next.js
next.js copied to clipboard
Fix scroll position being reset on back and forward navigation
This PR fixes the behavior that Next.js always resets the scroll position to (0, 0) on popState
, it's not noticeable because the browser corrects it after that. When explicitly set history.scrollRestoration
to 'manual'
we are able to reproduce it.
Also adds a test because the current ones only cover the scrollRestoration
experimental flag.
Fixes #20951.
Stats from current PR
Default Server Mode (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
buildDuration | 11.5s | 12s | ⚠️ +425ms |
nodeModulesSize | 42.7 MB | 42.7 MB | ⚠️ +56 B |
Page Load Tests Overall increase ✓
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
/ failed reqs | 0 | 0 | ✓ |
/ total time (seconds) | 2.203 | 2.229 | ⚠️ +0.03 |
/ avg req/sec | 1134.6 | 1121.73 | ⚠️ -12.87 |
/error-in-render failed reqs | 0 | 0 | ✓ |
/error-in-render total time (seconds) | 1.579 | 1.506 | -0.07 |
/error-in-render avg req/sec | 1583.62 | 1660.17 | +76.55 |
Client Bundles (main, webpack, commons) Overall increase ⚠️
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
677f882d2ed8..e7a0.js gzip | 13.4 kB | 13.4 kB | ⚠️ +5 B |
framework.HASH.js gzip | 39 kB | 39 kB | ✓ |
main-HASH.js gzip | 6.65 kB | 6.65 kB | ✓ |
webpack-HASH.js gzip | 751 B | 751 B | ✓ |
Overall change | 59.7 kB | 59.7 kB | ⚠️ +5 B |
Legacy Client Bundles (polyfills)
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
polyfills-HASH.js gzip | 31.3 kB | 31.3 kB | ✓ |
Overall change | 31.3 kB | 31.3 kB | ✓ |
Client Pages
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
_app-2a09aa2..4a98.js gzip | 1.28 kB | 1.28 kB | ✓ |
_error-8b758..aef6.js gzip | 3.46 kB | 3.46 kB | ✓ |
amp-e3e9bc99..932c.js gzip | 536 B | 536 B | ✓ |
hooks-5023ef..3670.js gzip | 888 B | 888 B | ✓ |
index-3a2b03..c677.js gzip | 227 B | 227 B | ✓ |
link-177412b..043e.js gzip | 1.67 kB | 1.67 kB | ✓ |
routerDirect..1a66.js gzip | 303 B | 303 B | ✓ |
withRouter-9..1b7d.js gzip | 302 B | 302 B | ✓ |
Overall change | 8.66 kB | 8.66 kB | ✓ |
Client Build Manifests
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
_buildManifest.js gzip | 347 B | 347 B | ✓ |
Overall change | 347 B | 347 B | ✓ |
Rendered Page Sizes Overall increase ⚠️
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
index.html gzip | 613 B | 614 B | ⚠️ +1 B |
link.html gzip | 620 B | 622 B | ⚠️ +2 B |
withRouter.html gzip | 608 B | 609 B | ⚠️ +1 B |
Overall change | 1.84 kB | 1.84 kB | ⚠️ +4 B |
Diffs
Diff for 677f882d2ed8..5ec6837e3.js
@@ -1701,7 +1701,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
as,
Object.assign({}, options, {
shallow: options.shallow && _this._shallow,
- locale: options.locale || _this.defaultLocale
+ locale: options.locale || _this.defaultLocale,
+ scroll: false
}),
forcedScroll
);
Diff for index.html
@@ -22,7 +22,7 @@
/>
<link
rel="preload"
- href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.42120b530b65ec6837e3.js"
+ href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.2c018116a9c3de3f916f.js"
as="script"
/>
<link
@@ -65,7 +65,7 @@
async=""
></script>
<script
- src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.42120b530b65ec6837e3.js"
+ src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.2c018116a9c3de3f916f.js"
async=""
></script>
<script
Diff for link.html
@@ -22,7 +22,7 @@
/>
<link
rel="preload"
- href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.42120b530b65ec6837e3.js"
+ href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.2c018116a9c3de3f916f.js"
as="script"
/>
<link
@@ -70,7 +70,7 @@
async=""
></script>
<script
- src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.42120b530b65ec6837e3.js"
+ src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.2c018116a9c3de3f916f.js"
async=""
></script>
<script
Diff for withRouter.html
@@ -22,7 +22,7 @@
/>
<link
rel="preload"
- href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.42120b530b65ec6837e3.js"
+ href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.2c018116a9c3de3f916f.js"
as="script"
/>
<link
@@ -65,7 +65,7 @@
async=""
></script>
<script
- src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.42120b530b65ec6837e3.js"
+ src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.2c018116a9c3de3f916f.js"
async=""
></script>
<script
Serverless Mode (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
buildDuration | 13.9s | 14.1s | ⚠️ +177ms |
nodeModulesSize | 42.7 MB | 42.7 MB | ⚠️ +56 B |
Client Bundles (main, webpack, commons) Overall increase ⚠️
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
677f882d2ed8..e7a0.js gzip | 13.4 kB | N/A | N/A |
framework.HASH.js gzip | 39 kB | 39 kB | ✓ |
main-HASH.js gzip | 6.65 kB | 6.65 kB | ✓ |
webpack-HASH.js gzip | 751 B | 751 B | ✓ |
677f882d2ed8..94af.js gzip | N/A | 13.4 kB | N/A |
Overall change | 59.7 kB | 59.7 kB | ⚠️ +5 B |
Legacy Client Bundles (polyfills)
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
polyfills-HASH.js gzip | 31.3 kB | 31.3 kB | ✓ |
Overall change | 31.3 kB | 31.3 kB | ✓ |
Client Pages
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
_app-2a09aa2..4a98.js gzip | 1.28 kB | 1.28 kB | ✓ |
_error-8b758..aef6.js gzip | 3.46 kB | 3.46 kB | ✓ |
amp-e3e9bc99..932c.js gzip | 536 B | 536 B | ✓ |
hooks-5023ef..3670.js gzip | 888 B | 888 B | ✓ |
index-3a2b03..c677.js gzip | 227 B | 227 B | ✓ |
link-177412b..043e.js gzip | 1.67 kB | 1.67 kB | ✓ |
routerDirect..1a66.js gzip | 303 B | 303 B | ✓ |
withRouter-9..1b7d.js gzip | 302 B | 302 B | ✓ |
Overall change | 8.66 kB | 8.66 kB | ✓ |
Client Build Manifests
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
_buildManifest.js gzip | 347 B | 347 B | ✓ |
Overall change | 347 B | 347 B | ✓ |
Serverless bundles Overall increase ⚠️
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
_error.js | 1.02 MB | 1.02 MB | ✓ |
404.html | 2.67 kB | 2.67 kB | ✓ |
500.html | 2.65 kB | 2.65 kB | ✓ |
amp.amp.html | 10.4 kB | 10.4 kB | ✓ |
amp.html | 1.86 kB | 1.86 kB | ✓ |
hooks.html | 1.92 kB | 1.92 kB | ✓ |
index.js | 1.02 MB | 1.02 MB | ✓ |
link.js | 1.08 MB | 1.08 MB | ⚠️ +23 B |
routerDirect.js | 1.07 MB | 1.07 MB | ⚠️ +23 B |
withRouter.js | 1.07 MB | 1.07 MB | ⚠️ +23 B |
Overall change | 5.27 MB | 5.27 MB | ⚠️ +69 B |
Webpack 5 Mode (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
buildDuration | 14.3s | 14.3s | ⚠️ +42ms |
nodeModulesSize | 42.7 MB | 42.7 MB | ⚠️ +56 B |
Page Load Tests Overall increase ✓
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
/ failed reqs | 0 | 0 | ✓ |
/ total time (seconds) | 2.167 | 2.134 | -0.03 |
/ avg req/sec | 1153.73 | 1171.77 | +18.04 |
/error-in-render failed reqs | 0 | 0 | ✓ |
/error-in-render total time (seconds) | 1.583 | 1.587 | 0 |
/error-in-render avg req/sec | 1578.79 | 1575.77 | ⚠️ -3.02 |
Client Bundles (main, webpack, commons) Overall increase ⚠️
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
597-74632e79..1d47.js gzip | 13.3 kB | 13.3 kB | ⚠️ +4 B |
framework.HASH.js gzip | 39.3 kB | 39.3 kB | ✓ |
main-HASH.js gzip | 6.6 kB | 6.6 kB | ✓ |
webpack-HASH.js gzip | 954 B | 954 B | ✓ |
Overall change | 60.1 kB | 60.1 kB | ⚠️ +4 B |
Legacy Client Bundles (polyfills)
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
polyfills-HASH.js gzip | 31.1 kB | 31.1 kB | ✓ |
Overall change | 31.1 kB | 31.1 kB | ✓ |
Client Pages
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
_app-aedc815..1421.js gzip | 1.26 kB | 1.26 kB | ✓ |
_error-71ec2..1a96.js gzip | 3.38 kB | 3.38 kB | ✓ |
amp-33a09cb0..6745.js gzip | 536 B | 536 B | ✓ |
hooks-4e968a..f870.js gzip | 902 B | 902 B | ✓ |
index-5c6845..f75c.js gzip | 230 B | 230 B | ✓ |
link-99f0c6c..b84a.js gzip | 1.65 kB | 1.65 kB | ✓ |
routerDirect..bb56.js gzip | 306 B | 306 B | ✓ |
withRouter-7..2133.js gzip | 302 B | 302 B | ✓ |
Overall change | 8.57 kB | 8.57 kB | ✓ |
Client Build Manifests
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
_buildManifest.js gzip | 326 B | 326 B | ✓ |
Overall change | 326 B | 326 B | ✓ |
Rendered Page Sizes Overall increase ⚠️
vercel/next.js canary | shuding/next.js fix-manual-scroll-restoration | Change | |
---|---|---|---|
index.html gzip | 586 B | 587 B | ⚠️ +1 B |
link.html gzip | 593 B | 592 B | -1 B |
withRouter.html gzip | 581 B | 582 B | ⚠️ +1 B |
Overall change | 1.76 kB | 1.76 kB | ⚠️ +1 B |
Diffs
Diff for 677f882d2ed8..eaa79e7a0.js
@@ -969,7 +969,8 @@
n,
Object.assign({}, o, {
shallow: o.shallow && i._shallow,
- locale: o.locale || i.defaultLocale
+ locale: o.locale || i.defaultLocale,
+ scroll: !1
}),
undefined
);
Diff for index.html
@@ -22,7 +22,7 @@
/>
<link
rel="preload"
- href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.45a1f5b1723eaa79e7a0.js"
+ href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.a973e2eb466e7e9c94af.js"
as="script"
/>
<link
@@ -43,7 +43,7 @@
"props": { "pageProps": {} },
"page": "/",
"query": {},
- "buildId": "8zTew-6sWr0fSIt2oV0ym",
+ "buildId": "oDhfaeVkUGJg9FA98dyTH",
"isFallback": false,
"gip": true
}
@@ -65,7 +65,7 @@
async=""
></script>
<script
- src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.45a1f5b1723eaa79e7a0.js"
+ src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.a973e2eb466e7e9c94af.js"
async=""
></script>
<script
@@ -77,11 +77,11 @@
async=""
></script>
<script
- src="/_next/static/8zTew-6sWr0fSIt2oV0ym/_buildManifest.js"
+ src="/_next/static/oDhfaeVkUGJg9FA98dyTH/_buildManifest.js"
async=""
></script>
<script
- src="/_next/static/8zTew-6sWr0fSIt2oV0ym/_ssgManifest.js"
+ src="/_next/static/oDhfaeVkUGJg9FA98dyTH/_ssgManifest.js"
async=""
></script>
</body>
Diff for link.html
@@ -22,7 +22,7 @@
/>
<link
rel="preload"
- href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.45a1f5b1723eaa79e7a0.js"
+ href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.a973e2eb466e7e9c94af.js"
as="script"
/>
<link
@@ -48,7 +48,7 @@
"props": { "pageProps": {} },
"page": "/link",
"query": {},
- "buildId": "8zTew-6sWr0fSIt2oV0ym",
+ "buildId": "oDhfaeVkUGJg9FA98dyTH",
"isFallback": false,
"gip": true
}
@@ -70,7 +70,7 @@
async=""
></script>
<script
- src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.45a1f5b1723eaa79e7a0.js"
+ src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.a973e2eb466e7e9c94af.js"
async=""
></script>
<script
@@ -82,11 +82,11 @@
async=""
></script>
<script
- src="/_next/static/8zTew-6sWr0fSIt2oV0ym/_buildManifest.js"
+ src="/_next/static/oDhfaeVkUGJg9FA98dyTH/_buildManifest.js"
async=""
></script>
<script
- src="/_next/static/8zTew-6sWr0fSIt2oV0ym/_ssgManifest.js"
+ src="/_next/static/oDhfaeVkUGJg9FA98dyTH/_ssgManifest.js"
async=""
></script>
</body>
Diff for withRouter.html
@@ -22,7 +22,7 @@
/>
<link
rel="preload"
- href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.45a1f5b1723eaa79e7a0.js"
+ href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.a973e2eb466e7e9c94af.js"
as="script"
/>
<link
@@ -43,7 +43,7 @@
"props": { "pageProps": {} },
"page": "/withRouter",
"query": {},
- "buildId": "8zTew-6sWr0fSIt2oV0ym",
+ "buildId": "oDhfaeVkUGJg9FA98dyTH",
"isFallback": false,
"gip": true
}
@@ -65,7 +65,7 @@
async=""
></script>
<script
- src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.45a1f5b1723eaa79e7a0.js"
+ src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.a973e2eb466e7e9c94af.js"
async=""
></script>
<script
@@ -77,11 +77,11 @@
async=""
></script>
<script
- src="/_next/static/8zTew-6sWr0fSIt2oV0ym/_buildManifest.js"
+ src="/_next/static/oDhfaeVkUGJg9FA98dyTH/_buildManifest.js"
async=""
></script>
<script
- src="/_next/static/8zTew-6sWr0fSIt2oV0ym/_ssgManifest.js"
+ src="/_next/static/oDhfaeVkUGJg9FA98dyTH/_ssgManifest.js"
async=""
></script>
</body>
Instead of just assigning to false
at least this should be configurable from somewhere. That would be the desired use-case
Hi @bayraak! The reason for directly using false
here is, no matter what the value of history.scrollRestoration
is, Next.js should never reset the scroll position to (0,0) when hitting back/forward buttons (also mentioned in the original issue comment by another maintainer: https://github.com/vercel/next.js/issues/20951#issuecomment-757941531). I can't think of any specific use case that you want to configure that.
The false
change in this PR will only affect the navigations triggered by history's popstate event, which are only back/forward. Link navigations are still configurable via scroll={false}
of <Link>
.
@shuding FYI, you can achieve the same behaviour by using the experimental scrollRestoration
flag -- in your next.config.js
, add:
module.exports = {
experimental: {
scrollRestoration: true
}
}
Related PR: https://github.com/vercel/next.js/commit/38bd1a024cb25923d8ea15f269a7294d073684d8
@mmazzarolo The issue that this PR fixes (#20951) is when window.history.scrollRestoration
is set to 'manual'
by the user, without enabling that experimental feature.
@shuding understood. Sorry, I missed it 👍
@shuding is this still planned to be reviewed and merged?
@JanKaifer oh you closed it! 👀
Is the functionality added in this PR already now in canary
(eg. through some other PR)? Or is there something which makes this irrelevant / unnecessary?
Last we checked (before Next.js 13 + app directory), the built-in scroll restoration in Next.js (both standard scroll restoration and the experimental.scrollRestoration
flag) was still not working properly when navigating back using the browser Back button.
We have a workaround mostly based on this Gist, but it seems unusual to have to do this.
Hi, this PR was stale and it's not a priority now. If you would like to pursue this PR, feel free to fork it and create your own.