smoothscroll-anchor-polyfill

⚓ Apply smooth scroll to anchor links to replicate CSS scroll-behavior

GitHub

Start

The Scroll Behavior specification allows for native smooth scrolling in browsers – both by using JavaScript scroll APIs like window.scrollTo and Element.scrollIntoView or by simply setting the property scroll-behavior to smooth in CSS, which will then make any scrolling smooth by default. This includes scrolls that are triggered by an anchor link pointing to an element on the page by targeting it's id in the hash, like <a href="#target">.
By using this CSS property, you can build a one-page design with smooth scroll between the different sections without having to write a single line of JS – just like this page is doing!

Unfortunately, the Scroll Behavior spec is not supported in all major browsers yet. 👎🏻
There are several Polyfills available to fix this, for example smoothscroll-polyfill. But even if you use those, navigation happening due to clicks on anchor elements is still instant without any smoothness: only the JavaScript APIs are polyfilled.
This little script aims to fix this. If the browser does not support native Scroll Behavior, it will wire up all matching anchor links so they use the (polyfilled and thus smooth) JS APIs for navigation. Let the scrolling begin!

Usage

⚠ Since this script uses the JavaScript scroll APIs and relies on their smooth scroll functionality to operate, you'll need a polyfill for the Scroll Behavior spec in order for this script to make a difference. It just wires up <a> tags and hashchange events to use window.scroll() and Element.scrollIntoView(). smoothscroll-polyfill is used as example throughout this site, but you may just as well use another polyfill – or write your own implementation. If you are using jQuery on your site, you could use $.animate() to provide smooth scroll for these scroll APIs, for example.

1. Setting scroll-behavior in CSS

Browsers don't parse CSS properties they don't recognize. For this reason, reading the scroll-behavior property from your regular stylesheets is unfortunately not possible (without a performance hit). Instead, you need to additionally specify scroll-behavior using a CSS variable:

<style>
  html {
    /* CSS custom property for the polyfill */
    --scroll-behavior: smooth;

    /* Normal CSS property for browsers with native support */
    scroll-behavior: smooth;
  }
<style>

You can treat it like any other property, for example use media queries or toggle classes.
The following only enables smooth scroll on Desktop devices:

<style>
  html {
    --scroll-behavior: auto;
    scroll-behavior: auto;
  }

  @media screen and (min-width: 1150px) {
    html {
      --scroll-behavior: smooth;
      scroll-behavior: smooth;
    }
  }
<style>

Need to support Internet Explorer?

In legacy browsers like Internet Explorer, CSS Custom Properties are not supported. To specify scroll-behavior, use one of the following options instead:

Using the inline style attribute:

<html style="scroll-behavior: smooth;">
...
</html>

This way, the polyfill can read the property using getAttribute('style') even if the browser doesn't parse it.

Using font-family as workaround

Alternatively, you can specify the property as the name of a custom font family. Your actual fonts will still work the way they should (plus, you can simply declare actual fonts on body instead of html).
As with CSS variables (and unlike inline styles), this allows you to use normal CSS features like media queries or classes.

<style>
  html {
    /* Normal CSS property for browsers with native support */
    scroll-behavior: smooth;

    /* Defined as the name of a font, so the polyfill can read it */
    font-family: "scroll-behavior: smooth", sans-serif;
  }
<style>

💡 Redeclaring your scroll-behavior properties to work with this polyfill can be automated using a PostCSS plugin. You simply write regular CSS and the plugin will intelligently transform it using one of the above options, depending on your supported browsers (detected via browserslist). It just works™


2. Installing the polyfill

Option 1: Using <script>

Simply drop in <script> tags linking to the polyfill(s) and you're good to go.

<!-- Any polyfill to enable smoothscroll for the JavaScript APIs -->
<script src="https://unpkg.com/smoothscroll-polyfill/dist/smoothscroll.min.js"></script>

<!-- This package, to apply the smoothscroll to anchor links -->
<script src="https://unpkg.com/smoothscroll-anchor-polyfill"></script>

Option 2: With npm

Alternatively, if you're using npm, you can install using npm install smoothscroll-anchor-polyfill and then use the polyfill by requiring/importing it in your JS.

// Import any polyfill to enable smoothscroll for JS APIs
import smoothscrollPolyfill from 'smoothscroll-polyfill';

// Import this package to apply the smoothscroll to anchor links
import smoothscrollAnchorPolyfill from 'smoothscroll-anchor-polyfill';

// (Unlike this package, smoothscroll-polyfill needs to be actively invoked: )
smoothscrollPolyfill.polyfill();

👉🏻 The polyfill is also provided in ES module format as index.mjs and index.min.mjs.

Advanced installation (with Code Splitting)

If you're using a build system with support for code splitting like Parcel or Webpack, you can use dynamic imports to load the polyfills – this way, browsers won't even download the polyfill code if they already have support for the Scroll Behavior spec natively:

// Only continue if polyfills are actually needed
if (!('scrollBehavior' in document.documentElement.style)) {

  // Wait until the Polyfills are loaded
  Promise.all([
    import('smoothscroll-polyfill'),
    import('smoothscroll-anchor-polyfill')
  ])
  // then use the modules however you want
  .then(([smoothscrollPolyfill, smoothscrollAnchorPolyfill]) => {
    // (Unlike this package, smoothscroll-polyfill needs to be actively invoked: )
    smoothscrollPolyfill.polyfill();
  });
}

Docs

For 90% of use cases, there should not be much more to it than loading this polyfill – it will execute immediately no matter if loaded through a script tag or in a module environment. If the Scroll Behavior spec is supported natively, the code won't do anything.

Changing the scroll behavior

The prefered way to dynamically adjust the scroll behavior is through CSS, e.g. toggling a class or using a media query. The documentation site is using this method: click the "Toggle smooth scroll" button and notice how the class smooth-scroll is toggled on <html>.

Valid property values for scroll-behavior are smooth to enable smooth scroll, or auto, initial, inherit or unset to use instant, jumping scroll.

You can also assign these values directly to document.documentElement.style.scrollBehavior, it will have precedence over all other ways of specyfing the scroll behavior.
Assigning to .scrollBehavior is not recommened however, as some packages use this property for feature detection and can break if you mess with it.

Using the polyfill even if there is native support

This package exports two methods, destroy and polyfill.
If loaded through a script tag, these methods are exposed on window.smoothscrollAnchorPolyfill.

polyfill({ force: boolean }):

The polyfill method starts the polyfill. If it is already active, it will simply restart – so you can safely call it without running destroy() first.
The method takes an (optional) Object as argument, if you set the property force to true, anchor navigation will be handled by this script even if the browser supports native smooth scroll. Not recommended.

destroy():

Disables the polyfill and removes all EventListeners.



Limitations

scroll-behavior is not detected in regular stylesheets

As already explained in the Usage section, scroll-behavior can not be set in regular CSS, as accessing the property there from JavaScript is not possible without a performance hit. This is caused by browsers not parsing a CSS property if it isn't recognized as valid. If you need the flexiblity of CSS, consider the font-family workaround.

scroll-behavior is only supported as global setting

In browsers with native support, you can define scroll-behavior at multiple points in your document, e.g. auto on the document itself, but smooth on a slideshow container that has separate scrolling. This polyfill does not allow for that, either all anchors on the page scroll smoothly by setting scroll-behavior at document level, or none.

scroll-behavior doesn't affect scrolling triggered from JavaScript

This polyfill only affects scrolling triggered by clicks on <a> tags and through hashchange events. You'll still have to pass { behavior: 'smooth' } when using APIs like window.scroll() unless your polyfill for these APIs has it's own CSS property check.

Inconsistencies in native implementations

While Scroll Behavior has native support in a couple of browsers already, they behave differently than expected in some situations. The following are not bugs of this polyfill, but inconsistencies of browsers' native behavior and workarounds you might want to know about.

Blink (e.g. Chrome, Opera):
While 'normal' scrolling is smooth, if you click a couple of links and then navigate back and forth using the browser's forwards/backwards buttons (which triggers a hashchange everytime), it jumps from anchor to anchor instead of scrolling smoothly.
If this is important to you, you can fix it by detecting the Blink engine and force-enabling this polyfill. Load browsengine.js, then do (before the polyfill runs):

if (window.webpage.engine.blink) {
          window.__forceSmoothscrollAnchorPolyfill__ = true;
}

Gecko (Firefox):
Anchors pointing to #top don't smooth scroll. Use anchors pointing at # for an easy fix.



FAQ

Will this break Server Side Rendering?

No.

Will this work if anchors are inserted after the script was loaded?

The polyfill uses Event Delegation to detect clicks, so even if an anchor is added to the page after the polyfill was loaded, everything should work.

Does this support prefers-reduced-motion?

prefers-reduced-motion is a relatively new CSS media query that hints at whether a client prefers less motion, which can be important for people with certain illnesses. Firefox currently is the only browser to support both scroll-behavior and prefers-reduced-motion and thus acts as a reference for the interplay between these two properties – and in Firefox, smooth scrolling is not disabled automatically if this media query matches.
So no, this polyfill does not automatically disable itself if the client prefers less motion, but yes, it supports prefers-reduced-motion the same way Firefox does – via a media query:

@media (prefers-reduced-motion: reduce) {
  html {
    --scroll-behavior: auto;
    scroll-behavior: auto;
  }
}

Rechtliches

Hinweis: die folgenden rechtlichen Hinweise betreffen diese Website als solche entsprechend deutschem und europäischem Recht, nicht das vorgestellte Software-Paket "smoothscroll-anchor-polyfill". "smoothscroll-anchor-polyfill" selbst ist lizensiert nach der MIT-Lizenz, mehr Informationen können dem GitHub Repository entnommen werden.

Impressum

Angaben gemäß §5 TMG

Jonas Kuske
Sielstraße 5
27568 Bremerhaven

Kontakt

Telefon: +491603336948
Mail: mail@jonaskuske.com

Verantwortlich für Inhalte gemäß 55 Abs. 2 RStV:

Jonas Kuske
Sielstraße 5
27568 Bremerhaven

Haftungsauschluss

Haftung für Inhalte

Die Inhalte dieser Seite wurden mit größter Sorgfalt erstellt. Für die Richtigkeit, Vollständigkeit und Aktualität der Inhalte kann ich jedoch keine Gewähr übernehmen. Als Diensteanbieter bin ich gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG bin ich als Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen. Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei Bekanntwerden von entsprechenden Rechtsverletzungen werde ich diese Inhalte umgehend entfernen.

Haftung für Links

Mein Angebot enthält Links zu externen Webseiten Dritter, auf deren Inhalte ich keinen Einfluss habe. Deshalb kann ich für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werde ich derartige Links umgehend entfernen.

Urheberrecht

Die durch die Seitenbetreiber erstellten bzw. verwendeten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht.

Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitte ich um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werde ich derartige Inhalte umgehend entfernen.

Datenschutz

Durch die Nutzung dieser Website erklären Sie sich mit der Erhebung, Verarbeitung und Nutzung von Daten gemäß der nachfolgenden Beschreibung einverstanden. Die Website kann grundsätzlich ohne Registrierung besucht werden. Dabei werden folgende Daten ggf. zu statistischen Zwecken auf dem Server, verwaltet von GitHub, in sogenannten "Server Log-Files" gespeichert, ohne dass diese Daten unmittelbar auf Ihre Person bezogen werden:

  • Besuchte Website
  • Uhrzeit zum Zeitpunkt des Zugriffes
  • Menge der gesendeten Daten in Bytes
  • Quelle/Verweis, von welchem Sie auf diese Seite gelangten
  • Verwendeter Browser
  • Verwendetes Betriebssystem
  • Verwendete IP-Adresse

Diese Seite verwendet den Dienst Google Fonts, um verschiedene Schriftarten einzubinden. Beim Abrufen der Schriftdateien, was bei Seitenaufruf automatisch geschieht, können die Daten, die oben aufgelistet sind, auch vom Dienstleister Google eingesehen werden.

Nehmen Sie mit dem Websitebetreiber durch die angebotenen Kontaktmöglichkeiten Verbindung auf, werden Ihre Angaben gespeichert, damit auf diese zur Bearbeitung und Beantwortung Ihrer Anfrage zurückgegriffen werden kann. Ohne Ihre Einwilligung werden diese Daten nicht an Dritte weitergegeben; auf Wunsch können Sie Einsicht in die gesammelten Daten bekommen oder eine vollständige Löschung selbiger veranlassen.

Legal

Note: the legalities discussed here concern this website itself, not the software package "smoothscroll-anchor-polyfill", and are required for compliance with German & European law. "smoothscroll-anchor-polyfill" itself is licensed under a plain MIT license, for more information check out the respective GitHub repository.

Imprint

Information in accordance with section §5 TMG

Jonas Kuske
Sielstraße 5
27568 Bremerhaven

Contact

Phone: +491603336948
Mail: mail@jonaskuske.com

Person responsible for content in accordance with 55 Abs. 2 RStV:

Jonas Kuske
Sielstraße 5
27568 Bremerhaven

Disclaimer

Accountability for content

The contents of our pages have been created with the utmost care. However, we cannot guarantee the contents' accuracy, completeness or topicality. According to statutory provisions, we are furthermore responsible for our own content on these web pages.In this context, please note that we are accordingly not obliged to monitor merely the transmitted or saved information of third parties, or investigate circumstances pointing to illegal activity. Our obligations to remove or block the use of information under generally applicable laws remain unaffected by this as per §§ 8 to 10 of the Telemedia Act(TMG).

Accountability for links

Responsibility for the content of external links (to web pages of third parties) lies solely with the operators of the linked pages. No violations were evident to us at the time of linking. Should any legal infringement become known to us, we will remove the respective link immediately.

Copyright

Our web pages and their contents are subject to German copyright law.

Privacy

With the use of this website you agree to the collection and processing of data as described below. The website can be visited with out prior sign-up, when visiting the site the following data might be stored on the server (managed by GitHub) in the form of so-called "server log files" for statistical use.

  • Visited website
  • Time when website was loaded
  • Amount of data sent in bytes
  • Source/referer which lead you to this site
  • Used browser
  • Used operating system
  • Used IP address

This website is using service Google Fonts to load font files. While loading the font files – which happens automatically when visiting this site – the pieces of data listed above might be gathered and stored by service provider Google as well.

If you contact the operator of this website through the given contact possibilities your given information will be stored solely to reply to and process your inquiry. Without your permission collected information will never be shared with third parties. At your request you can gain insight into or request the complete deletion of all data collected about you.