vue-router scrollBehaviour not working properly in some environments

Created on 25 May 2017  ·  13Comments  ·  Source: vuejs/vue-router

Version

2.5.3

Reproduction link

https://samknows.com/

Steps to reproduce

Sorry for no minimal reproduction - I have honestly no idea where to start with this, or even whether it is a bug in vue-router (I suspect it is).

The ONLY place we have managed to reproduce it is on our live website. Not locally, not on staging environments, just here: https://samknows.com/

The bug:

  1. Scroll halfway down homepage
  2. Click "The Whitebox" link in header

What is expected?

Scroll handler should have taken you to the top of the page

What is actually happening?

You're not at the top of the page


Here is my router code right now:

const router = new VueRouter({
  mode: 'history',
  scrollBehavior: (to, from, savedPosition) => {
    console.log(to, from);

    if (to.name.startsWith('products') && from.name.startsWith('products')) {
      return null;
    }

    return savedPosition || { x: 0, y: 0 };
  },
  routes,
});

As you can see in the console, the from route is wrong. What could be causing this? Why is it only happening in some environments, and what can I give you to help?

Sorry for vagueness.

need repro

Most helpful comment

Hi there,

I'm facing a similar issue where scrollBehavior is not working. I think it is due to the fact that window.scrollTo doesn't properly work if you have stricky div elements, andor peculiar nested CSS.

I found a workaround using Element.scrollIntoView.

In my case the following code solved the issue:

scrollBehavior: (to, from, savedPosition) => {
        // very bad, maybe better use a Navigation Guard?
        document.getElementById('app').scrollIntoView();
        return null;
    }

_(tested only with Chrome so far)_

Maybe this bug could be re-opened to make sure scrollBehavior can handle this scenario. Ie: if a String is returned it should be considered as an Element's id, therefore scrollIntoView should be applied instead of scrollTo.

_edit: minor fixes_

All 13 comments

Nice animation 😎

A minimal repro would help us. If it depends on the environment, that's quite unusual and unfortunately for you, probably unrelated with vue-router. Maybe the server is adding some headers? I don't know. You could try setting up a simple repro pushing it to that server and then downloading the resulting html file to check it against the staging server.

Thanks!

Heh, it's quite unusual and I can't see how it can be related to _anything_ - it just shouldn't be happening! However, the to and from objects both being the same, and the from object being wrong - can anything outside of vue-router cause that to happen?

Can't really make a minimal repro without replicating it locally :( I will carry on trying to replicate this and figure out what's causing it. Have already sunk a couple days into it, and it's basically just a link.

😩

I was thinking that you could try testing that minimal repro on the server (not the whole app), maybe you see the difference that way

Our staging environment is running on exactly the same server and it isn't happening there, usually. A few deploys back, it was happening on staging, but it went away when I added the console.log.

I'm closing this for the moment, come back if you get more information 🙂

I met the same problem. Does any body know why?
BTW, NICE Animation!

absolutely no idea. worked around it in the end:

  scrollBehavior: (to, from, savedPosition) => {
    // This is the workaround
    if (to.name === 'products' && from.name === 'products') {
      return savedPosition || { x: 0, y: 0 };
    }

    if (to.name.startsWith('products') && from.name.startsWith('products')) {
      return null;
    }

    return savedPosition || { x: 0, y: 0 };
  },

Hi there,

I'm facing a similar issue where scrollBehavior is not working. I think it is due to the fact that window.scrollTo doesn't properly work if you have stricky div elements, andor peculiar nested CSS.

I found a workaround using Element.scrollIntoView.

In my case the following code solved the issue:

scrollBehavior: (to, from, savedPosition) => {
        // very bad, maybe better use a Navigation Guard?
        document.getElementById('app').scrollIntoView();
        return null;
    }

_(tested only with Chrome so far)_

Maybe this bug could be re-opened to make sure scrollBehavior can handle this scenario. Ie: if a String is returned it should be considered as an Element's id, therefore scrollIntoView should be applied instead of scrollTo.

_edit: minor fixes_

thanks @lordgordon your comment was very helpful .. I use it in a Global After Hook like this and it works well:

// scroll to top on routes navigation

router.afterEach((to, from) => {
  document.getElementById('app').scrollIntoView()
})

For anyone still getting this issue;

I had an overflow: auto on the html tag. Removing it fixed the issue!

I know it been a while. But here is what i do

scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition
    } else {
      const isHash = to.hash ? to.hash.split('#') : undefined
      if (isHash) {
        let tmp = setTimeout(() => {
          document.getElementById(isHash[1]).scrollIntoView()
          clearTimeout(tmp)
        })
      }
      return null
    }
  },

setTimeout is import for the change of micro task. It will be execute at the end

This works for me to simply scroll to top for every route:

const router = new VueRouter({
  mode: 'history',
  routes: [...routes],
  scrollBehavior () {
    document.body.scrollTop = 0; // For Safari
    document.documentElement.scrollTop = 0;
  },
});

@wuestkamp that will break the expected scroll position behaviour when pressing the back button, though

Was this page helpful?
0 / 5 - 0 ratings