diff --git a/app/assets/javascripts/discourse/app/components/glimmer-site-header.gjs b/app/assets/javascripts/discourse/app/components/glimmer-site-header.gjs index 3c690da5393..05dbc656800 100644 --- a/app/assets/javascripts/discourse/app/components/glimmer-site-header.gjs +++ b/app/assets/javascripts/discourse/app/components/glimmer-site-header.gjs @@ -105,7 +105,16 @@ export default class GlimmerSiteHeader extends Component { let headerWrapBottom = this._headerWrap.getBoundingClientRect().bottom - overscrollPx; - // While scrolling on iOS, fixed elements can have a viewport position which fluctuates between -1 and 1. + // iOS Safari bug: when overscrolling at the bottom of the page on iOS, fixed/sticky elements report their position incorrectly. + // Clamp the headerWrapBottom to the minimum possible value (top + height) to avoid this. + const minimumPossibleHeaderWrapBottom = + headerCssTop + this._headerWrap.getBoundingClientRect().height; + headerWrapBottom = Math.max( + headerWrapBottom, + minimumPossibleHeaderWrapBottom + ); + + // Safari bug: while scrolling on iOS, fixed elements can have a viewport position which fluctuates by sub-pixel amounts. // To avoid that fluctuation affecting the header offset, we subtract that tiny fluctuation from the header-offset. const headerWrapTopDiff = this._headerWrap.getBoundingClientRect().top -