WKWebView: does scrollView.bounces = false survive WebKit's overscroll-behavior updates? (Capacitor iOS, fixed tab bar lifts on overscroll)
Capacitor 8 iOS app (WKWebView, contentInset 'never', viewport-fit=cover) with a position: fixed; bottom: 0 tab bar. On iOS 26, pulling past the end of a page lifts the bar off the bottom of the screen together with the content. Scrolling from code (window.scrollTo) keeps the bar pinned, so only the touch rubber-band moves it. The usual fixes are webView.scrollView.bounces = false or CSS overscroll-behavior: none on the root. Several reports (Apple forums, iOS 16 era) say the WebView still slides after setting bounces = false, implying WebKit resets it on every layer-tree commit, the way it once reset app-set decelerationRate. Which one wins, and is the native flag safe to rely on?
The client flag wins, and WebKit can only make bouncing stricter, never re-enable it. In WebKit main, WKScrollView keeps separate flags: _bouncesSetByClient (written by the public setBounces:) and _bouncesHorizontalInternal / _bouncesVerticalInternal (written by _setBouncesInternal:vertical:). The internal flags are what the iOS scrolling-node delegate sets from the main frame's overscroll-behavior on each scrolling-tree commit (WKWebViewIOS.mm calls it with the main frame's horizontal and vertical overscroll behavior). The effective value is ANDed:
- (void)_updateBouncability {
[super setBouncesHorizontally:(_bouncesSetByClient && _bouncesHorizontalInternal)];
[super setBouncesVertically:(_bouncesSetByClient && _bouncesVerticalInternal)];
}(Source/WebKit/UIProcess/ios/WKScrollView.mm)
So setting it once after the WebView exists is enough. Overscroll-behavior commits can't undo it. In Capacitor, do it in a CAPBridgeViewController subclass:
class AppBridgeViewController: CAPBridgeViewController {
override open func capacitorDidLoad() {
webView?.scrollView.bounces = false
webView?.scrollView.alwaysBounceVertical = false // WKScrollView inits this to YES
}
}CSS overscroll-behavior: none on html reaches the same AND through the internal flag, but only for pages that carry it. The native flag covers every page, including error and onboarding routes. Separately, check that short pages aren't scrollable by accident: min-height: 100dvh on a shell plus padding-bottom for the tab bar on body leaves every page scrollable by the bar's height, so there's always something to pull. Size the shell as calc(100dvh - <bar height incl. safe-area-inset-bottom>).
Verified by reading WebKit main's WKScrollView.mm and the iOS scrolling-node delegate source. Programmatic scrolling was confirmed in the iOS 26.5 simulator; the touch overscroll fix was not yet confirmed on a device.