Nuxt.js: screen jumps to top before page change

Created on 15 Jan 2018  路  18Comments  路  Source: nuxt/nuxt.js

Issue

scrollToTop fires before page change

To Reproduce

Create 2 pages, A and B, linking B to a with a nuxt-link.
Make sure A is long enough to be able to scroll down.
When you scroll down on page A and click on the nuxt-link to go to page B, then page A will first scroll to the top before transitioning to page B.

I am using Chrome Version 63.0.3239.132

My issue seems to be the same as #1036 but it was closed?? Any update on this?

This question is available on Nuxt.js community (#c2257)

Most helpful comment

Indeed, this is still an issue even with the latest version.
To note I'm using the universal/SSR mode.

All 18 comments

Same issue here. I know there has been a lot of discussion around scrolling issues in #1036,

1376 and others, but this issue definitely persists for us at least. It would be great to have some clarity on the actual current status, workarounds, etc....or whether we are just completely missing something... Thanks!

I added the following to my nuxt.config.js. It doesn't fix the back button jump, but still gives a better user experience

router: { scrollBehavior: function (to, from, savedPosition) { return {x: false, y: false} } },

Hi, I am also having the same problem, I noticed that the scroll function is called before the page is mounted. Whereas it's the other way round for my other non-ssr vue apps.

I think the desired behavior would be that the scrollToTop would be triggered _after_ page A transitions out, and _before_ page B transitions in:

Current sequence:

  1. User scrolls down PageA and clicks a <nuxt-link/> for PageB
  2. Nuxt fires scrollToTop; which shows the top of PageA
  3. PageA transitions out (eg. fade out)
  4. PageB transitions in (eg. fade in)

Ideal sequence:

  1. User scrolls down PageA and clicks a <nuxt-link/> for PageB
  2. PageA transitions out (eg. fade out)
  3. Nuxt fires scrollToTop. No "page" is shown because we're between transitions
  4. PageB transitions in (eg. fade in)

I think a lot of this has to do with the Vue Router flow (and maybe less to do with Nuxt). Below is the navigation flow. Not sure where the scroll behavior / transitions fit into this.

  1. The Full Navigation Resolution Flow
  2. Navigation triggered.
  3. Call leave guards in deactivated components.
  4. Call global beforeEach guards.
  5. Call beforeRouteUpdate guards in reused components (2.2+).
  6. Call beforeEnter in route configs.
  7. Resolve async route components.
  8. Call beforeRouteEnter in activated components.
  9. Call global beforeResolve guards (2.5+).
  10. Navigation confirmed.
  11. Call global afterEach hooks.
  12. DOM updates triggered.
  13. Call callbacks passed to next in beforeRouteEnter guards with instantiated instances.

This should be resolved with latest nuxt. If not please update us.

@husayt just checked it out, and yes the screen jump is gone! However now it doesn't go to the top of the 'to' page.

A working work-around fix of using a custom scrollBehavior in route option in nuxt.config.js: https://github.com/nuxt/nuxt.js/issues/2738#issuecomment-372007743.

None of the solutions proposed above have worked for me, but wrapped my container in component worked ! Hope this will help someone !

@raphaelaitelalim What do you mean by "wrapped my container in component" ? What container / component are you talking about ? We don't even know the structure you're working on.

@RandomPiche Sorry about that, so i wanted to say "wrapped my container in component".

My code look like this :

``html <template> <no-ssr> <div> some content... </div> </no-ssr> </template>

I have same issue @raphaelnoguier still after wrapped my container in component

@saicharan96 Okay can i see your layout/default.vue and nuxt config ?

Thanks

Hello there,

I know this issue is marked as closed but I just had the same problem. I'm up to date with Nuxt version, I tried the different solutions proposed here without success.

Worst is I have the bug on a remote environment but not when I run the web-app locally. It appears once then disappears without me doing anything. I'm a bit lost :o

Thanks for your help!

Indeed, this is still an issue even with the latest version.
To note I'm using the universal/SSR mode.

My workaround for this problem (in some cases) is page transition with 'in-out' mode, set scrollToTop to false in component, and manually update document.documentElement.scrollTop after trasition ends.

<script>
//page component
export default {
  scrollToTop: false, //disable this option in component

  transition: {
    name: "page",
    mode: "in-out",
    afterEnter(el) {
      // reset scroll position
      document.documentElement.scrollTop = 0;
      ...
    }
  }
}
</script>
<style>
/* 
=================
example page transition
=================
*/

.page-enter-active,
.page-leave-active {
  overflow: hidden;
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  visibility: hidden; 
  z-index: 200;
}
</style>

This is not very flexible soluion, not tested with async data, but maybe help someone. Example

My workaround:

  • In your layout, surround <Nuxt /> component with a <transition />
  • Attach a function emitting e.g. 'page-after-leave' to $root on @after-leave hook
  • In /app/router.scrollBehavior.js listen to the emit:
export default (to, from, savedPosition) => {
    const nuxt = window['<%= globals.nuxt %>']; // in case you don't use the default $nuxt

    let position = { // default, mimics the top position on navigation
        x: 0,
        y: 0,
    };

    if (isRouteWhereYouHandleScrollPositionManually) { // for custom scrollPosition setting from inside the page / component
        position = false;
    } else if (savedPosition) {
        position = savedPosition;
    }

    return new Promise((resolve) => {
        nuxt.$root.$once('page-after-leave', () => {
            nuxt.$nextTick(() => {
                resolve(position);
            });
        });
    });
};

It's a bit on overhead with additional <transition /> but it works very stable, no jumps!

EDIT: and this is the css for the <Nuxt /> transition:

&-transition {
    &-leave-active {
        transition: all 1ms linear;
    }
}

Attach a function emitting e.g. 'page-after-leave' to $root on @after-leave hook

@pooledge Can you please give an example?

@tre-dev I am also using this solution and works fine so far. Just emit custom event in @after-leave transition hook, and listen for it in custom /app/router.scrollBehavior.js file as described above. $root is global object and can be used as global event bus.

<script>
export default {
  ... 
  transition: {
    name: "page",
    ...
    afterLeave(el) {
      this.$root.$emit('page-after-leave');
      ...
    }
    ...
  }
}
</script>
Was this page helpful?
0 / 5 - 0 ratings

Related issues

vadimsg picture vadimsg  路  3Comments

VincentLoy picture VincentLoy  路  3Comments

bimohxh picture bimohxh  路  3Comments

vadimsg picture vadimsg  路  3Comments

surmon-china picture surmon-china  路  3Comments