fix(theme-common): use native scrolling when smooth behavior set in CSS (#7057)

* fix(theme-common): use native scrolling when smooth behavior set in CSS

* fix

* fix again

* fix again
This commit is contained in:
Joshua Chen 2022-03-29 18:02:09 +08:00 committed by GitHub
parent 77662260f8
commit 4e45e14fdd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -16,6 +16,7 @@ import React, {
} from 'react'; } from 'react';
import {useDynamicCallback, ReactContextError} from './reactUtils'; import {useDynamicCallback, ReactContextError} from './reactUtils';
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
import useIsBrowser from '@docusaurus/useIsBrowser';
type ScrollController = { type ScrollController = {
/** A boolean ref tracking whether scroll events are enabled. */ /** A boolean ref tracking whether scroll events are enabled. */
@ -233,14 +234,6 @@ export function useScrollPositionBlocker(): {
}; };
} }
// Not all have support for smooth scrolling (particularly Safari mobile iOS)
// TODO proper detection is currently unreliable!
// see https://github.com/wessberg/scroll-behavior-polyfill/issues/16
const SupportsNativeSmoothScrolling = false;
// const SupportsNativeSmoothScrolling =
// ExecutionEnvironment.canUseDOM &&
// 'scrollBehavior' in document.documentElement.style;
type CancelScrollTop = () => void; type CancelScrollTop = () => void;
function smoothScrollNative(top: number): CancelScrollTop { function smoothScrollNative(top: number): CancelScrollTop {
@ -260,10 +253,7 @@ function smoothScrollPolyfill(top: number): CancelScrollTop {
(!isUpScroll && currentScroll < top) (!isUpScroll && currentScroll < top)
) { ) {
raf = requestAnimationFrame(rafRecursion); raf = requestAnimationFrame(rafRecursion);
window.scrollTo( window.scrollTo(0, Math.floor((currentScroll - top) * 0.85) + top);
0,
Math.floor(Math.abs(currentScroll - top) * 0.85) + top,
);
} }
} }
rafRecursion(); rafRecursion();
@ -275,8 +265,9 @@ function smoothScrollPolyfill(top: number): CancelScrollTop {
/** /**
* A "smart polyfill" of `window.scrollTo({ top, behavior: "smooth" })`. * A "smart polyfill" of `window.scrollTo({ top, behavior: "smooth" })`.
* This currently always uses a polyfilled implementation, because native * This currently always uses a polyfilled implementation unless
* support detection seems unreliable. * `scroll-behavior: smooth` has been set in CSS, because native support
* detection for scroll behavior seems unreliable.
* *
* This hook does not do anything by itself: it returns a start and a stop * This hook does not do anything by itself: it returns a start and a stop
* handle. You can execute either handle at any time. * handle. You can execute either handle at any time.
@ -296,12 +287,22 @@ export function useSmoothScrollTo(): {
cancelScroll: CancelScrollTop; cancelScroll: CancelScrollTop;
} { } {
const cancelRef = useRef<CancelScrollTop | null>(null); const cancelRef = useRef<CancelScrollTop | null>(null);
const isBrowser = useIsBrowser();
// Not all have support for smooth scrolling (particularly Safari mobile iOS)
// TODO proper detection is currently unreliable!
// see https://github.com/wessberg/scroll-behavior-polyfill/issues/16
// For now, we only use native scroll behavior if smooth is already set,
// because otherwise the polyfill produces a weird UX when both CSS and JS try
// to scroll a page, and they cancel each other.
const supportsNativeSmoothScrolling =
isBrowser &&
getComputedStyle(document.documentElement).scrollBehavior === 'smooth';
return { return {
startScroll: (top: number) => { startScroll: (top: number) => {
cancelRef.current = SupportsNativeSmoothScrolling cancelRef.current = supportsNativeSmoothScrolling
? smoothScrollNative(top) ? smoothScrollNative(top)
: smoothScrollPolyfill(top); : smoothScrollPolyfill(top);
}, },
cancelScroll: () => cancelRef?.current, cancelScroll: () => cancelRef.current?.(),
}; };
} }