iOS下无法阻止`touchmove`事件导致的窗口滚动问题求助
Ah, I’ve dealt with this exact headache in Mobile Safari before—let’s break down what’s going on and how to fix it.
The Issue You’re Encountering
You’re trying to implement custom scrolling on a target element while locking the main window from scrolling. Your approach is:
- Listen to the
window'stouchmoveevent - Programmatically scroll your target element
- Call
event.preventDefault()to block window scroll
But in Mobile Safari, the window still scrolls underneath your element. This isn’t a mistake in your code—it’s a known WebKit bug.
The bug causes
preventDefault()on window-leveltouchmoveevents to fail to block main frame scrolling when a child element is being scrolled programmatically, which matches exactly the behavior you’re seeing.
A Reliable Workaround
Instead of fighting WebKit’s default scroll handling, we can explicitly define which elements are allowed to handle touch actions using CSS, then adjust our event listeners to target the right element:
- Lock the body’s touch behaviors: Add
touch-action: none;to your<body>CSS. This tells the browser not to handle default touch actions like scrolling on the main window. - Mark your target as the scroll container: Give your scrollable element
overflow: auto;(orscroll) andtouch-action: pan-y;(usepan-xfor horizontal scrolling) to let the browser know it’s the intended scroll target. - Move your listener to the target element: Attach the
touchmovelistener directly to your scrollable element instead of the window. This ensures the browser prioritizes the element’s scroll over the window’s, and lets you handle scroll bounds if needed.
Example Code
Here’s how to implement this:
CSS:
body { touch-action: none; /* Disable default window touch scrolling */ margin: 0; } .scrollable-element { overflow: auto; touch-action: pan-y; /* Allow vertical scrolling on this element */ height: 80vh; /* Fixed height to enable scrolling */ padding: 1rem; border: 1px solid #eee; }
JavaScript:
const scrollElement = document.querySelector('.scrollable-element'); scrollElement.addEventListener('touchmove', (e) => { // Optional: Check if we've reached the scroll bounds const isAtTop = scrollElement.scrollTop === 0; const isAtBottom = scrollElement.scrollTop + scrollElement.clientHeight >= scrollElement.scrollHeight; // Keep preventDefault if you want to block window scroll even at bounds if (!isAtTop && !isAtBottom) { e.preventDefault(); } });
This approach bypasses the WebKit bug entirely by setting clear scroll priorities upfront, instead of trying to override the window’s behavior after the fact.
内容的提问来源于stack exchange,提问作者Matthew Gertner




