Disable Body Scrolling For Open Modals on iOS Devices
When overflow: hidden just isn’t enough
Stacey Marks, Engineer
Feb. 18, 2020
Are you creating a website that has a full page modal and want to stop pesky body background scrolling when the modal is open?
Did you realize the method that pretty much works everywhere doesn’t work for Safari on iPhones?
Did you google how to fix this?
Did all of the answer pages point you to the
And when you tested the most recent version of it on a phone, it didn’t work?
After scouring the internet for way too many hours, more than I care to admit, I found two solutions that worked for what we needed.
1. Stop everything from scrolling, both body background and everything inside modal.
2. Stop the background from scrolling, while allowing content inside the modal to scroll.
THE FIRST EXAMPLE - Freeze Everything
The first block of code is checking if we are indeed in Safari on an iPhone, otherwise we run what works for literally everything else.
The second block, we are checking if the modal is open, then run what’s needed to stop everything from scrolling.
Easy enough, right?
But wait! What if I actually need to be able to scroll inside my modal?
We got you covered.
THE SECOND EXAMPLE - Allow Scrolling Inside Modal
For context, this is all in the modal component and only gets called once the modal is actually open. In addition, the
_.includes is from the Lodash library, which would have to be imported at the top of your component.
So, because the site is built using Gatsby, we had to take advantage of
useEffect in order to access the DOM element to grab the document.
#terms-text-container, which is the container that contains (ha) the modal’s text, not the entire modal itself. We are just targeting the
div that we want to be able to scroll.
After checking if we are in mobile iOS Safari, we want to grab all the nodes (the text, in this case) inside
#terms-text-container and add them to the
insideTextModal array, which you will see being used later. If we don’t do this and your finger hits a piece of text, it will register as the text <p> but wont register as
#terms-text-container and disable scrolling.
Then we add the event listener. Because it's a phone scroll the action is
touchmove and we call our method
handleTouchMove below, which is defined just below.
handleTouchMove, if the
(what our finger touches and moves) is either NOT the
#terms-text-container, or anything inside of it, which is represented with the array
preventDefault, aka stop it from scrolling
And once the modal is closed, we remove the
touchmove event listener, and that’s it!
OTHER (PERSONAL) TAKEAWAYS
Removing Event Listeners
In order to properly remove an event listener, what you pass to the
removeEventListener must be the same as what you passed into the
QA’ing your iPhone Specific Work
When testing iPhone specific situations like this, the issue may not be able to be replicated in the browser, even when using responsive mode. We were only able to see this issue when testing on an iPhone itself, or later, using the Xcode simulator, which was a life saver!!
Have a different way to solve this issue? Please let us know!