Open soosap opened 4 years ago
@soosap can you please provide more information on this issue?
Basically this isn't working on gatsby => enableBodyScroll(document.body);
The body does get overflow hidden but the scrolling isn't stopped.
same issue here for my gatsby project... style="overflow: hidden;"
is applied to the body element but this does not prevent scrolling.
I know nothing about Gatsby, but assuming gatsbyjs.org is developed using Gatsby, it forces the <html>
element to scroll:
Someone made it work on gatsby?
@AidanRRR Can you try replacing all instances of document.body
with document.documentElement
in body-scroll-lock
and see if that helps?
It works, thanks!
Confirmed this fixes my issue in a gatsby project as well, I have to hide overflow in the root in componentDidMount
and delete that in componentWillUnmount
. Any consideration for how this might still be incorporated into gatsby projects in a more general way?
@mdhornet90 by root do you mean the <html>
element?
Are you sure you replaced the document.body
on this line? It should apply overflow on the <html>
element if you did.
Yes, I'm referring to the <html>
element. I didn't want to modify the library in place or fork a custom version of BSL so this code:
componentDidMount() {
this.scrollRef = this.scrollRef || React.createRef();
document.documentElement.style.overflow = 'hidden';
disableBodyScroll(this.scrollRef.current);
}
componentWillUnmount() {
clearAllBodyScrollLocks();
document.documentElement.style.overflow = null;
}
Does the trick for my specific situation (overlay that prevents scrolling of everything except the content of the overlay)
Well, perhaps we could restrict overflow of both <body>
and <html>
...can you think of any issues with this @willmcpo ?
I had to do this:
// for disabling
React.useEffect(() => {
document.getElementsByTagName("html")[0].style.overflow = "hidden";
disableBodyScroll(document.body);
}, []);
// for enabling
React.useEffect(() => {
enableBodyScroll(document.body);
document.getElementsByTagName("html")[0].style = "";
}, []);
I am not using gatsby, though I have noticed the same issues when doing SSR where disableBodyScroll
is called on the server, and then enableBodyScroll
on client.
When calling enableBodyScroll
, this lib checks its previousBodyOverflowSetting
and previousBodyPaddingRight
variables to know what to revert to re-enabling scrolling. However those variables will never be set when the environment in which scrolling is disabled (the server doing SSR) is different to the environment where scrolling is enabled (the browser)
I imagine this issue is the same for gatsby, where scroll is disabled at build time, and enabled on the client.
I propose: instead of storing previous values in a variable, store in a data-*
attribute on the body, since these will be persisted across server/client (or build-time/run-time). I have tested this locally and it seems to work. I can make a PR if you like
@WickyNilliams why is disableBodyScroll
called in an SSR environment?
@lizy0329 A solution for this might be to change body-scroll-lock
to prevent overflow on both document.body
and document.documentElement
. I don't have time to do that right now, but if anyone would like to try and test that approach then submit a PR that would be great!
@diachedelic excuse the delay, forgot to respond!
It's called in server because I may want to show a modal pre-opened on page load. I'm sure there are plenty of other use-cases besides.
In any case, whether calling at build-time (SSG) and server-side (SSR) the problem is the same - the assumption that enabling and disabling scrolling will always happen in the same environment
Hopefully I am making sense here :)
@WickyNilliams If I were you I would avoid locking the scroll in anything but a browser environment, as it just does not make sense to do so on the server. Is a way for you to determine which environment you are in?
@diachedelic shall i create a separate issue to discuss? I feel I am distracting from the original issue here (i misread originally, which is why i commented here, but this issue is not related to my question)...
I think there are valid reasons to call on the server, and from a dev perspective the less you have to special-case the server environment, the better. I have a few ideas in mind that could work that would be small changes, and backwards compatible.
@WickyNilliams Yes, this belongs in a seperate issue. But I think you need to understand that disableScrollLock adds event listeners etc, it does not just modify the DOM. It just does not make sense to call it in a server environment. You should call it immediately after "rehydration" if you need a modal to appear immediately.
I was also having this problem, in Gatsby v2.32.10, with body-scroll-lock v3.1.5. My requirement was to lock the scroll when a modal side-navigation "drawer" was open.
The solution in https://github.com/willmcpo/body-scroll-lock/issues/154#issuecomment-612664227 improved the situation, but I also had to dynamically set the height
style of the #gatsby-focus-wrapper
div, like this:
const [isOpen, setIsOpen] = useState(false); // represents the open state of the navigation drawer
const headerEl = useRef();
useEffect(() => {
if (typeof window === 'undefined') return;
const gatsbyDiv = document.getElementById('gatsby-focus-wrapper');
if (isOpen) {
gatsbyDiv.style.height = '100%';
document.documentElement.style.overflow = 'hidden';
disableBodyScroll(headerEl.current);
} else {
gatsbyDiv.style.height = 'auto';
document.documentElement.style.overflow = 'auto';
enableBodyScroll(headerEl.current);
}
return clearAllBodyScrollLocks();
}, [isOpen]);
@hellodavecooper It's more likely there could be a potential issue with one part of your solution - you are setting overflow
to auto
on closing but auto
isn't a default value of overflow
and it has a little bit different behavior. I suggest setting overflow
to visible
as it is a default value of this property.
In order to lock the scrolling in a gatsby project, the
overflow: hidden
style property must be set on the root<html style="overflow: hidden;">
element.