Vue Router Scroll Behavior

2021 . Nov . 16 / Web DevelopmentNotes++ to self

The problem

Sometimes, when using Vue Router, we can get lost while navigating inside our app, especially when using the browser history.

E.g., let's say we are at the home page and we scroll down, then we click on a link to another page of the site. Now we are at the bottom of the new page (or at least at the same scroll position that we were at the last one). We scroll up and then press the back button on the browser; now we are not at the same position we were before getting into the new page.

Probably not a big deal for some cases, but we can improve this behavior.

The Solution

The Vue Router documentation gives us the necessary code fragments to fix this issue:

Always scroll to the top

We can always start at the top of the page. This way we don't have to do unnecessary scrolling.

top
scrollBehavior (to, from, savedPosition) {
    return { x: 0, y: 0 };
}

Get back to the saved position

When getting back or forth on the browser history, we'll get to the last position we were.

savedPosition
scrollBehavior (to, from, savedPosition) {
    if (savedPosition) {
        return savedPosition;
    }
}

Scroll to anchor

Now if we have some anchors in the page (i.e., #scroll-to-anchor), we have to tell the router.

#anchor
scrollBehavior (to, from, savedPosition) {
    if (to.hash) {
        return {
            selector: to.hash
        }
    }
}

Full Solution

Now, we can just mix all the pevious code into one solution (used Blog on this too):

app/router.scrollBehavior.js
// Non-nuxt: scrollBehavior (to, from, savedPosition) { ... }
export default function(to, from, savedPosition) {
    if (to && to.hash) {
        return {
            selector: to.hash,
            offset: { x: 0, y: 80 }, // avoid blocking the view when having fixed components
            behavior: 'smooth'
        };
    } else if (savedPosition) {
        return savedPosition;
    } else {
        return { x: 0, y: 0 };
    }
}

Let's break it down:

  • As we are using Nuxt, according to Nuxt docs this code needs to be in a specific file inside a specific directory: app/router.scrollBehavior.js

  • First we check if we are trying to go to an anchor in the page. Then if there is a saved position (just like navigating through browser history), we return it. And last but not least, we just return the top of the page as the default behavior.

  • Now, there are two properties more in the anchor object. behavior: 'smooth': is just the eye candy. offset: as we have an app bar that is fixed at the top of the page, we need to scroll just enought to make the anchored content to be below the bar, and not under it, so the content doesn't get blocked in the view. Try it by clicking here; the title "The Solution" will get positioned bellow the app bar.

  • The last point can also be done with plain css:

css
html {
    scroll-padding-top: 80px;
    scroll-behavior: smooth;
}
Comments
If you have any doubt or question, or know how to improve this post, please feel free to write a comment.