Reputation: 448
I'm setting up a website using Gatsby 2.2.10 and the Link components are retaining the scroll positions of the previous page and not scrolling back to the top when they're clicked.
<div className="Footer__legal body">
<p>© {new Date().getFullYear()} My Nice Company</p>
<Link to="/privacy-policy">Privacy Policy</Link>
<Link to="/page-2">Page 2 Link component</Link>
</div>
Expected behaviour:
When you click 'Privacy Policy', 'Page 2' or any page at the bottom of the website, I expect the page to load with user being back at the top.
Actual Behaviour:
User stays at scroll position of the current page
Upvotes: 22
Views: 15484
Reputation: 250
This seems to be a bug in Gatsby when css html { scroll-behavior: smooth; }
is used in conjunction with a sticky element. Gatsby contributor in Github says they should have this patched soon. In that same PR comment he offers a workaround.
Ive added a bit more to this workaround to allow jump links like www.yoursite.com/#scroll-down-to-important-info
// This would go in gatsby-browser.js
exports.shouldUpdateScroll = ({ routerProps: { location }, getSavedScrollPosition }) => {
const currentPosition = getSavedScrollPosition(location);
if (!location.hash){
setTimeout(() => {
window.scrollTo({ top: (currentPosition[0] || 0), left: (currentPosition[1] || 0), behavior: 'instant' });
}, 0);
return false;
}
};
Upvotes: 2
Reputation: 104
In my case the problem was that I had set scroll-behavior: smooth, on the html element like this:
html {
scroll-behavior: smooth;
}
After removing this property new pages would be opened without any scroll.
Upvotes: 3
Reputation: 183
To further some of the answers above, I had to stick a time out in the useEffect to get it to work consistently. Seems to work with a timeout as little as 1ms.
useEffect(() => {
let windowScrollTimeout = setTimeout(() => {
window.scrollTo(0, 0)
clearTimeout(windowScrollTimeout)
}, 1)
}, [])
Upvotes: 0
Reputation: 53
I have a header set with position: fixed;
and then a div with margin-top: 100px;
so my content starts below the header (that has a 100px height). I had the scrolling issue until I changed margin to padding: padding-top: 100px;
Upvotes: 1
Reputation: 2341
If your page is a functional component, you can use the useEffect
hook to scroll back to the top of the page, assuming that you are using graphql
and so your component takes some data as an argument. This way every time that data
changes, you scroll to the top of the page(works similar to componentDidUpdate).
const PageCmp = ({ data }) => {
...
useEffect(() => {
window.scrollTo(0,0)
}, [data])
...
}
Upvotes: 5
Reputation: 6051
In my CSS, I had
html, body {
height: 100%;
overflow-y: scroll;
}
because it was the only way to fix a mobile-safari-only bug (my favorites!)
If you also can't get rid of overflow
properties, I suggest this:
// in gatsby-browser.js
export function shouldUpdateScroll(prevRouterProps, { location }) {
window.scrollTo(0, 0)
const body = document.getElementsByTagName('body')[0]
body.scrollTop = 0
return false
}
Upvotes: 1
Reputation: 358
My problem was that I had html {height: 100%}
. Removing that rule seemed to have solved the problem.
I also have gatsby-plugin-transition-link
in my project, which has added more wrappers around my main content.
Upvotes: 1
Reputation: 1125
useEffect(() => window.scrollTo(0, 0), [])
solved the issue for me. I was having the problem only on firefox but not on chrome. Idk what was causing the issue but it works fine now.
Upvotes: 4
Reputation: 21
Ok, this is an old question, but I've recently faced the same odd behavior. Turns out my problem was different from all other solutions I've seen in the internet so far.
Gatsby uses a package called gatsby-react-router-scroll
. This package manages Gatsby's scroll behavior. This behavior is mainly implemented in Scroll Handler component. This component only scrolls up in componentDidUpdate
method, and not in the componentDidMount
one. I've added a debugger
in the componentDidMount
method and ScrollHandler component was being re-mounted at each navigation.
The fix was to figure out why this component was being mounted and remounted at each navigation. In my case, I had a React.StrictMode
component on wrapRootElement
function in my gatsby-browser.js
. Removing StrictMode made ScrollHandler component stable, thus solving my problem.
Upvotes: 2
Reputation: 169
If you have overflow: hidden
or overflow: auto
set on body
, you'll have this issue!
Upvotes: 11
Reputation: 448
Figured out a workaround by converting index.js page into a class-based component and then added
componentDidUpdate() {
window.scrollTo(0,0);
}
Not the cleanest fix nor do I know why it wasn't scrolling automatically, going to a JS meet up next week so will ask the question then and post a follow up if I get an answer.
I have a feeling it's something to do with my styles, as I started a new project and the Gatsby-cli had no issues. Will be refactoring styles to see if this fixes the issue.
Note: Returning to this following Michael's answer, it also related to an overflow: hidden;
style I had on the body, removing this also fixed my issue.
Upvotes: 1
Reputation: 3455
You can also modify gatsby-browser.js
and implement a hook for each scroll update:
// in gastby-browser.js
exports.shouldUpdateScroll = ({
routerProps: { location },
getSavedScrollPosition,
}) => {
const { pathname } = location
// list of routes for the scroll-to-top-hook
const scrollToTopRoutes = [`/privacy-policy`, `/page-2`]
// if the new route is part of the list above, scroll to top (0, 0)
if (scrollToTopRoutes.indexOf(pathname) !== -1) {
window.scrollTo(0, 0)
}
return false
}
You will find the code for shouldUpdateScroll
on GitHub or in the documentation for shouldUpdateScroll
on the GatsbyJS website.
Upvotes: 9