Search code examples
javascripthtmlgoogle-chromemicrosoft-edgebrowser-api

ScrollToOptions' behavior: 'smooth' broken in Chrome and Edge v81+


After testing in BrowserStack, I've concluded that using scrollTo() with option parameter behavior: smooth does not work in Chrome and Edge since version 81. Version 80 of both Edge and Chrome was working as expected. According to MDN, it should be working with no asterisk. (unlike Safari)

In popular answers such as this one, using behavior: smooth is the recommended way to enable smooth-scrolling in your web application.

Here's a small reproducible:

<html>
<button onclick="goToAnchor('b')">Scroll to B</button>
<div id="a" style="height: 1000px; background-color: blue;">Blue</div>
<div id="b" style="height: 1000px; background-color: red;">Red</div>
<div id="c" style="height: 1000px; background-color: green;">Green</div>

</html>

<script>
  function goToAnchor(anchor) {
    let rect = document.getElementById(anchor).getBoundingClientRect();
    window.scrollTo({
      left: rect.left + window.pageXOffset,
      top: rect.top + window.pageYOffset,
      behavior: 'smooth',
    });
  }
</script>

The expected behavior would be that the browser window smoothly interpolate the view down to the red div. It does this properly in all versions of Firefox I've tested. In all of the versions of Chrome since v81, and all versions of Edge since v81, it seems to use the behavior of behavior: auto - i.e. it jumps to the div rather than smoothly interpolating the view.

In version 80 of both Edge and Chrome, it behaves just like Firefox, meaning this bug (?) must've been introduced in version 81 - perhaps in the shared Chromium code-base?

I find it very unlikely that I am the first person to find this issue, as it has been not been working since April, and must therefore conclude I am doing something wrong. Can someone point towards the error in the code? Or is the Chrome and Edge APIs really broken? Is the behavior hidden behind a feature flag, like in Safari?


Solution

  • I believe I've found the culprit, and interestingly, it seems it is Firefox that is the odd one out.

    In this StackOverflow thread about detecting RDP connections, the current top answer says:

    You can use the following media query:

    @media screen and (prefers-reduced-motion: reduce) { . . . }
    

    The prefers-reduced-motion part is interesting. It seems in my testing that this also changes scrollTo() calls with scroll-behavior: 'smooth' to jump rather than interpolate.

    I did an addendum to the question's code example to demo the feature:

    <html>
      <button onclick="goToAnchor('b')">Scroll to B</button>
      <p class="reduced-motion">Reduced motion is enabled.</p>
      <div id="a" style="height: 1000px; background-color: blue;">Blue</div>
      <div id="b" style="height: 1000px; background-color: red;">Red</div>
      <div id="c" style="height: 1000px; background-color: green;">Green</div>
    </html>
    <style>
      .reduced-motion {
        display: none;
      }
      @media (prefers-reduced-motion) {
        .reduced-motion {
          display: inline;
        }
      }
    </style>
    <script>
      function goToAnchor(anchor) {
        let rect = document.getElementById(anchor).getBoundingClientRect();
        window.scrollTo({
          left: rect.left + window.pageXOffset,
          top: rect.top + window.pageYOffset,
          behavior: 'smooth',
        });
      }
    </script>

    It will now say "Reduced motion is enabled." next to the button depending on your OS and browser configuration. In that case, the scrollTo call will simply jump rather than interpolate.

    In short, the issue is that BrowserStack's remote desktop control is also enabling this flag.