From 75bccde3747fbd7d8a39367923d6d3e89765798e Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Thu, 2 Nov 2017 04:21:02 +0100 Subject: [PATCH] fix(block-scroll-strategy): disable smooth scrolling before restoring scroll position (#8132) Disables user-defined `scroll-behavior: smooth` before restoring the scroll position when disabling the `BlockScrollStrategy`, which prevents browsers from animating the scroll position change. Fixes #7139. --- .../scroll/block-scroll-strategy.spec.ts | 21 +++++++++++++++++++ .../overlay/scroll/block-scroll-strategy.ts | 20 +++++++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/cdk/overlay/scroll/block-scroll-strategy.spec.ts b/src/cdk/overlay/scroll/block-scroll-strategy.spec.ts index ef2d9e131f8b..6126e3a3b8f2 100644 --- a/src/cdk/overlay/scroll/block-scroll-strategy.spec.ts +++ b/src/cdk/overlay/scroll/block-scroll-strategy.spec.ts @@ -136,6 +136,27 @@ describe('BlockScrollStrategy', () => { expect(document.documentElement.getBoundingClientRect().width).toBe(previousContentWidth); }); + it('should not clobber user-defined scroll-behavior', skipIOS(() => { + const root = document.documentElement; + const body = document.body; + + root.style['scrollBehavior'] = body.style['scrollBehavior'] = 'smooth'; + + // Get the value via the style declaration in order to + // handle browsers that don't support the property yet. + const initialRootValue = root.style['scrollBehavior']; + const initialBodyValue = root.style['scrollBehavior']; + + overlayRef.attach(componentPortal); + overlayRef.detach(); + + expect(root.style['scrollBehavior']).toBe(initialRootValue); + expect(body.style['scrollBehavior']).toBe(initialBodyValue); + + // Avoid bleeding styles into other tests. + root.style['scrollBehavior'] = body.style['scrollBehavior'] = ''; + })); + /** * Skips the specified test, if it is being executed on iOS. This is necessary, because * programmatic scrolling inside the Karma iframe doesn't work on iOS, which renders these diff --git a/src/cdk/overlay/scroll/block-scroll-strategy.ts b/src/cdk/overlay/scroll/block-scroll-strategy.ts index df517a41436b..b828a96b97b4 100644 --- a/src/cdk/overlay/scroll/block-scroll-strategy.ts +++ b/src/cdk/overlay/scroll/block-scroll-strategy.ts @@ -45,11 +45,25 @@ export class BlockScrollStrategy implements ScrollStrategy { /** Unblocks page-level scroll while the attached overlay is open. */ disable() { if (this._isEnabled) { + const html = document.documentElement; + const body = document.body; + const previousHtmlScrollBehavior = html.style['scrollBehavior'] || ''; + const previousBodyScrollBehavior = body.style['scrollBehavior'] || ''; + this._isEnabled = false; - document.documentElement.style.left = this._previousHTMLStyles.left; - document.documentElement.style.top = this._previousHTMLStyles.top; - document.documentElement.classList.remove('cdk-global-scrollblock'); + + html.style.left = this._previousHTMLStyles.left; + html.style.top = this._previousHTMLStyles.top; + html.classList.remove('cdk-global-scrollblock'); + + // Disable user-defined smooth scrolling temporarily while we restore the scroll position. + // See https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior + html.style['scrollBehavior'] = body.style['scrollBehavior'] = 'auto'; + window.scroll(this._previousScrollPosition.left, this._previousScrollPosition.top); + + html.style['scrollBehavior'] = previousHtmlScrollBehavior; + body.style['scrollBehavior'] = previousBodyScrollBehavior; } }