Introduction
This tutorial assumes you have some knowledge on React and Sass (scss).
Sticky or fixed navigation bars is a popular design choice since it gives users an easy-to-reach access to navigate a web application or website.
However, it takes up space especially on smaller screens and might cover content in a way that's not appealing.
Possible Solution :- Smart Navbar
A smart navbar stays visible when a user is at the top of the page. The navbar is also visible when the user makes a scroll upwards from wherever they are on the page and it is hidden when the user makes a scroll downwards of the page.
Let's look at the code for the .jsx
function Navbar(){
return (
<nav className='nav'>
<div className='mainDiv'>
<span>
Logo
</span>
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</div>
</nav>
}
And the code for the .css
.nav {
position: fixed;
width: 100%;
z-index: 999;
top: 0;
right: 0;
left: 0;
padding: 0.3rem 0;
transition: all 200ms ease-in-out;
.mainDiv {
display: flex;
justify-content: space-between;
align-items: center;
}
}
We can define some state variables to keep track of the nav and modify it accordingly
const [atTop, setAtTop] = useState(true);
const [scrollDirection, setScrollDirection] = useState('');
We need to detect when a user is scrolling the page and the direction of their scroll. A user is scrolling down if the value of their last scroll position is less than the value of their current scroll position.
useEffect(() => {
const threshold = 0;
let lastScrollY = window.pageYOffset;
let ticking = false;
const updateScrollDirection = () => {
const scrollY = window.pageYOffset;
if (Math.abs(scrollY - lastScrollY) < threshold) {
ticking = false;
return;
}
setScrollDirection(scrollY > lastScrollY ? "down" : "up");
lastScrollY = scrollY > 0 ? scrollY : 0;
ticking = false;
};
const onScroll = () => {
if (!ticking) {
window.requestAnimationFrame(updateScrollDirection);
ticking = true;
}
};
window.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
}, [scrollDirection]);
We can use this logic to detect when the page is scrolling down and toggle our styling
// navbar.jsx
<nav className={'nav ${scrollDir === 'down' ? 'isScrollingDown' : '' }'}>
...
</nav>
If the user is scrolling down we add the .isScrollingDown
class and if the user is scrolling up, we simply remove the class
// style.scss
.isScrollingDown {
transform: translateY(-100%);
}
Performance
When working with scroll events, it is important to pay great attention to performance as we might call a function too many times which can have adverse effects.
In the above useEffect
we only update the state scrollDirection
when the user scrolls in the opposite direction.
We can also check for when the user is at the top of the page and utilize a throttle function to update styles or perform other logic.
Briefly, a throttle function can be defined as a higher order function that acts as a timer for the function passed into it.
Let's see an example of a throttle function
// initialize a throttleWait variable for performance
let throttleWait;
const throttle = (callback, time) => {
// if the variable is true, don't run the function
if (throttleWait) return;
// set the wait variable to true to pause the function
throttleWait = true;
// use setTimeout to run the function within the specified time
setTimeout(() => {
callback();
// set throttleWait to false once the timer is up to restart the throttle function
throttleWait = false;
}, time);
};
We can make use of the throttle function in a useEffect to perform logic as we wish.
const navbarControl = () => {
if (window.scrollY < 50) {
setAtTop(true);
} else {
setAtTop(false);
}
};
useEffect(() => {
window.addEventListener("scroll", () => throttle(navbarControl, 500));
return () => {
window.removeEventListener("scroll", throttle);
};
}, []);
With this implementation, the navbarControl
function is called only once every 500 milliseconds
Conclusion
So, there we have it: a smart navigation implementation with React and Sass for styling. Now users have easy access to navigate the web app/website without losing real estate in a way that blocks content on the page.
Top comments (0)