Home / Admin / frontend/js/snippets/scroll-behavior/sticky
Duplicate Snippet

Embed Snippet on Your Site

frontend/js/snippets/scroll-behavior/sticky

This JavaScript snippet enables smooth scrolling to in-page anchors (like #section1) while automatically adjusting for a sticky or fixed header. It improves navigation in long, single-page layouts and ensures that the target section’s heading is not hidden beneath the top navigation bar.

The script uses modern ES6 syntax and includes several enhancements for accessibility, user preference respect, and URL behavior.

Code Preview
php
<?php
<!-- Example: your sticky header -->
<header id="site-header" style="position:sticky;top:0;height:72px;">...</header>
document.addEventListener("DOMContentLoaded", () => {
  // Customize this to match your sticky header (or set to null if not needed)
  const HEADER_SELECTOR = "#site-header";
  const getHeaderOffset = () => {
    const header = HEADER_SELECTOR && document.querySelector(HEADER_SELECTOR);
    return header ? header.getBoundingClientRect().height : 0;
  };
  const prefersReduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
  const scrollToTarget = (target) => {
    if (!target) return;
    // Calculate top position minus sticky header height
    const headerOffset = getHeaderOffset();
    const elementY = window.pageYOffset + target.getBoundingClientRect().top;
    const y = Math.max(elementY - headerOffset, 0);
    window.scrollTo({
      top: y,
      behavior: prefersReduced ? "auto" : "smooth"
    });
    // Accessibility: ensure keyboard focus lands on the section
    // (won’t change visuals; helps screen reader/keyboard users)
    target.setAttribute("tabindex", "-1"); // temporary, safe for sections/headings
    target.focus({ preventScroll: true });
    target.addEventListener("blur", () => target.removeAttribute("tabindex"), { once: true });
  };
  // Click handler for internal anchors
  document.querySelectorAll('a[href^="#"]:not([href="#"])').forEach((anchor) => {
    anchor.addEventListener("click", (e) => {
      const id = anchor.getAttribute("href").slice(1);
      const target = document.getElementById(id);
      if (!target) return;
      e.preventDefault();
      // Update URL hash (keeps deep-linking and back button behavior)
      history.pushState(null, "", `#${id}`);
      scrollToTarget(target);
    });
  });
  // If page loads with a hash (or user navigates via back/forward), scroll correctly
  const handleHashNavigation = () => {
    const id = window.location.hash && window.location.hash.slice(1);
    if (!id) return;
    const target = document.getElementById(id);
    if (target) scrollToTarget(target);
  };
  window.addEventListener("hashchange", handleHashNavigation);
  handleHashNavigation(); // run once on load
});

Comments

Add a Comment