Content focused sites usually improve the user experience by reducing the distraction when it’s possible. And one way to achieve this is by hiding the navbar when the user scrolls down, and show it back when scrolls up.
Achieving this behavior in vue is very easy. So, let me show you how to do this. But before that, check out this demo on CodePen:
Step 1: Create the navbar
We’ll only need a single component for this demo: App.vue
. So, create it, then run it using Instant Prototyping:
vue serve App.vue
Next, put this in the template section:
<template>
<div class="app">
<div class="navbar" :class="{ 'navbar--hidden': !showNavbar }"></div>
</div>
</template>
The navbar is just a simple div that gets hidden when showNavbar
is false
.
We haven’t defined showNavbar
or the .navbar-hidden
class yet.
Let’s start with the .navbar-hidden
first. So in your css section, put the following:
<style>
* {
box-sizing: border-box;
}
body {
padding: 0;
margin: 0;
}
.app {
width: 100vw;
height: 500vh;
background: hsl(200, 50%, 90%);
}
.navbar {
height: 60px;
width: 100vw;
background: hsl(200, 50%, 50%);
position: fixed;
box-shadow: 0 2px 15px rgba(71, 120, 120, 0.5);
transform: translate3d(0, 0, 0);
transition: 0.1s all ease-out;
}
.navbar.navbar--hidden {
box-shadow: none;
transform: translate3d(0, -100%, 0);
}
</style>
Notes on what’s important here:
- We have
height: 500vh
on.app
to have room for scrolling (just to test our work). - The navbar has
position: fixed
, to make it sticky while we’re scrolling. - When the navbar is hidden, we update its
transform: translate3d
to move it up exactly the same amount as its height (it’s better to usetranslate3d
as opposed to justtranslate
ortranslateY
for performance reasons).
Step 2: Hide it when scrolling down
To hide the navbar, we just have to set showNavbar
to false
. But we should do this only when the user scrolls down. And we can detect the scrolling direction by storing the last scroll position and compare it to the current scroll position. If currentScrollPosition < lastScrollPosition
we show the navbar — we hide it, otherwise.
So, we need to define two data properties: showNavbar
and lastScrollPosition
.
<script>
export default {
data () {
return {
showNavbar: true,
lastScrollPosition: 0
}
}
}
</script>
Now, when the page is loaded, we need to listen for the scroll
event on window
.
mounted () {
window.addEventListener('scroll', this.onScroll)
},
beforeDestroy () {
window.removeEventListener('scroll', this.onScroll)
}
Let’s now implement the handler:
methods: {
onScroll () {
// Get the current scroll position
const currentScrollPosition = window.pageYOffset || document.documentElement.scrollTop
// Because of momentum scrolling on mobiles, we shouldn't continue if it is less than zero
if (currentScrollPosition < 0) {
return
}
// Here we determine whether we need to show or hide the navbar
this.showNavbar = currentScrollPosition < this.lastScrollPosition
// Set the current scroll position as the last scroll position
this.lastScrollPosition = currentScrollPosition
}
}
If you check it in the browser, you will see the navbar hiding once you start scrolling down (even by one pixel). But you might want for a few pixels to pass before hiding or showing it. We can achieve this with a simple check in the handler.
Step 3: Add scroll offset before hiding or showing the navbar
Update the onScroll
method to become like this:
onScroll () {
const currentScrollPosition = window.pageYOffset || document.documentElement.scrollTop
if (currentScrollPosition < 0) {
return
}
// Stop executing this function if the difference between
// current scroll position and last scroll position is less than some offset
if (Math.abs(currentScrollPosition - this.lastScrollPosition) < 60) {
return
}
this.showNavbar = currentScrollPosition < this.lastScrollPosition
this.lastScrollPosition = currentScrollPosition
}
So with this change, we don’t update showNavbar
until the difference between the current scroll position and the last scroll position is less than the offset we choose (60px
in this example).
That’s it! Now your navbar should be hidden/shown if you scroll down/up more than 60px.