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 72ba3d0b904..be18abe84cd 100644 --- a/app/assets/javascripts/discourse/app/components/glimmer-site-header.gjs +++ b/app/assets/javascripts/discourse/app/components/glimmer-site-header.gjs @@ -90,16 +90,28 @@ export default class GlimmerSiteHeader extends Component { return; } - // clamping to 0 to prevent negative values (hello, Safari) - const headerWrapBottom = Math.max( + // We expect this to be zero, but when overscrolling in Safari it can have a non-zero value: + const overscrollPx = Math.max( 0, - Math.floor(this._headerWrap.getBoundingClientRect().bottom) + document.documentElement.getBoundingClientRect().top ); + const headerWrapTop = + this._headerWrap.getBoundingClientRect().top - overscrollPx; + let headerWrapBottom = + this._headerWrap.getBoundingClientRect().bottom - overscrollPx; + + // While scrolling on iOS, an element fixed to the top of the screen can have a `top` which fluctuates + // between -1 and 1. To avoid that fluctuation affecting the header offset, we subtract that tiny fluctuation from the bottom value. + if (Math.abs(headerWrapTop) < 1) { + headerWrapBottom -= headerWrapTop; + } + let mainOutletOffsetTop = Math.max( 0, - Math.floor(this._mainOutletWrapper.getBoundingClientRect().top) - - headerWrapBottom + this._mainOutletWrapper.getBoundingClientRect().top - + headerWrapBottom - + overscrollPx ); if (DEBUG && isTesting()) { @@ -111,16 +123,19 @@ export default class GlimmerSiteHeader extends Component { } const docStyle = document.documentElement.style; + const currentHeaderOffset = parseInt(docStyle.getPropertyValue("--header-offset"), 10) || 0; - const newHeaderOffset = headerWrapBottom; + const newHeaderOffset = Math.floor(headerWrapBottom); if (currentHeaderOffset !== newHeaderOffset) { docStyle.setProperty("--header-offset", `${newHeaderOffset}px`); } const currentMainOutletOffset = parseInt(docStyle.getPropertyValue("--main-outlet-offset"), 10) || 0; - const newMainOutletOffset = headerWrapBottom + mainOutletOffsetTop; + const newMainOutletOffset = Math.floor( + headerWrapBottom + mainOutletOffsetTop + ); if (currentMainOutletOffset !== newMainOutletOffset) { docStyle.setProperty("--main-outlet-offset", `${newMainOutletOffset}px`); }