smoothAnchors.ts 1.6 KB

12345678910111213141516171819202122232425262728293031323334
  1. // Implements smooth scrolling when clicking on an anchor link.
  2. // This is required instead of using modern CSS because Chromium does not currently support scrolling
  3. // one element with scrollTo while another element is scrolled because of a click on a link. This would
  4. // thus not work with the ToC scrollspy and e.g. footnotes.
  5. // Here are additional links about this issue:
  6. // - https://stackoverflow.com/questions/49318497/google-chrome-simultaneously-smooth-scrollintoview-with-more-elements-doesn
  7. // - https://stackoverflow.com/questions/57214373/scrollintoview-using-smooth-function-on-multiple-elements-in-chrome
  8. // - https://bugs.chromium.org/p/chromium/issues/detail?id=833617
  9. // - https://bugs.chromium.org/p/chromium/issues/detail?id=1043933
  10. // - https://bugs.chromium.org/p/chromium/issues/detail?id=1121151
  11. const anchorLinksQuery = "a[href]";
  12. function setupSmoothAnchors() {
  13. document.querySelectorAll(anchorLinksQuery).forEach(aElement => {
  14. let href = aElement.getAttribute("href");
  15. if (!href.startsWith("#")) {
  16. return;
  17. }
  18. aElement.addEventListener("click", clickEvent => {
  19. clickEvent.preventDefault();
  20. let targetId = aElement.getAttribute("href").substring(1);
  21. // The replace done on ':' is here for footnotes, as this character would otherwise interfere when used as a CSS selector.
  22. let target = document.querySelector(`#${targetId.replace(":", "\\:")}`) as HTMLElement;
  23. window.history.pushState({}, "", aElement.getAttribute("href"));
  24. scrollTo({ top: target.offsetTop, behavior: "smooth" });
  25. });
  26. });
  27. }
  28. export { setupSmoothAnchors };