From 78b310faa306e0a59101f30ffafeee04879925ea Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Wed, 20 Jul 2022 22:57:50 +0100 Subject: [PATCH] Scroll to element in hash after hero height is set There's a bit of manually re-implementing what browsers already do here, but it's very simple and works very nicely --- static/src/js/base.js | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/static/src/js/base.js b/static/src/js/base.js index 67fbeee..94a7cb5 100644 --- a/static/src/js/base.js +++ b/static/src/js/base.js @@ -13,6 +13,12 @@ function setHeroHeight() { ROOT.style.setProperty("--hero-height", `${getHeroHeight()}px`); } +function scrollToElement(element, behavior = "smooth") { + const rect = element.getBoundingClientRect(); + const top = rect.top - getHeroHeight(); + window.scrollBy({ top: top, behavior }); +} + function handleHeroStuck() { if (HERO.getBoundingClientRect().top === 0) { HERO.classList.add("stuck"); @@ -39,11 +45,7 @@ window.addEventListener("load", () => { document.querySelectorAll("#table-of-contents li a").forEach((element) => { element.addEventListener("click", (event) => { event.preventDefault(); - const rect = document - .querySelector(event.target.hash) - .getBoundingClientRect(); - const top = rect.top - getHeroHeight(); - window.scrollBy({ top: top, behavior: "smooth" }); + scrollToElement(document.querySelector(event.target.hash)); }); }); @@ -56,7 +58,23 @@ window.addEventListener("load", () => { }); }); +window.addEventListener("DOMContentLoaded", () => { + setHeroHeight(); + + let scrollTarget = null; + try { + scrollTarget = document.getElementById(window.location.hash.slice(1)); + } catch { + // Probably an invalid selector - just ignore it + } + + if (!scrollTarget) { + return; + } + + scrollToElement(scrollTarget, "auto"); +}); + window.addEventListener("resize", debounce(setHeroHeight, 2000)); -window.addEventListener("load", setHeroHeight); window.addEventListener("scroll", throttle(handleHeroStuck, 100));