Smooth scroll anchor links WITHOUT jQuery

JavascriptHyperlinkAnchor

Javascript Problem Overview


Is it possible to use smooth scroll to anchor links but without jQuery? I am creating a new site and I don't want to use jQuery.

Javascript Solutions


Solution 1 - Javascript

Extending this answer: https://stackoverflow.com/a/8918062/3851798

After defining your function of scrollTo, you can pass the element you want to scrollTo in the function.

function scrollTo(element, to, duration) {
    if (duration <= 0) return;
    var difference = to - element.scrollTop;
    var perTick = difference / duration * 10;

    setTimeout(function() {
        element.scrollTop = element.scrollTop + perTick;
        if (element.scrollTop === to) return;
        scrollTo(element, to, duration - 10);
    }, 10);
}

If you have a div with an id="footer"

<div id="footer" class="categories">…</div>

In the script that you run to scroll you can run this,

elmnt = document.getElementById("footer");
scrollTo(document.body, elmnt.offsetTop, 600);

And there you have it. Smooth scrolling without jQuery. You can actually play around with that code on your browser's console and fine tune it to your liking.

Solution 2 - Javascript

Using the function from here: https://stackoverflow.com/questions/11213259/javascript-animation and modifying it to modify a property (not only a style's property), you can try something like this:

DEMO: http://jsfiddle.net/7TAa2/1/

Just saying...

function animate(elem, style, unit, from, to, time, prop) {
  if (!elem) {
    return;
  }
  var start = new Date().getTime(),
    timer = setInterval(function() {
      var step = Math.min(1, (new Date().getTime() - start) / time);
      if (prop) {
        elem[style] = (from + step * (to - from)) + unit;
      } else {
        elem.style[style] = (from + step * (to - from)) + unit;
      }
      if (step === 1) {
        clearInterval(timer);
      }
    }, 25);
  if (prop) {
    elem[style] = from + unit;
  } else {
    elem.style[style] = from + unit;
  }
}

window.onload = function() {
  var target = document.getElementById("div5");
  animate(document.scrollingElement || document.documentElement, "scrollTop", "", 0, target.offsetTop, 2000, true);
};

div {
  height: 50px;
}

<div id="div1">asdf1</div>
<div id="div2">asdf2</div>
<div id="div3">asdf3</div>
<div id="div4">asdf4</div>
<div id="div5">asdf5</div>
<div id="div6">asdf6</div>
<div id="div7">asdf7</div>
<div id="div8">asdf8</div>
<div id="div9">asdf9</div>
<div id="div10">asdf10</div>
<div id="div10">asdf11</div>
<div id="div10">asdf12</div>
<div id="div10">asdf13</div>
<div id="div10">asdf14</div>
<div id="div10">asdf15</div>
<div id="div10">asdf16</div>
<div id="div10">asdf17</div>
<div id="div10">asdf18</div>
<div id="div10">asdf19</div>
<div id="div10">asdf20</div>

Solution 3 - Javascript

Actually, there is more lightweight and simple way to do that: https://codepen.io/ugg0t/pen/mqBBBY

function scrollTo(element) {
  window.scroll({
    behavior: 'smooth',
    left: 0,
    top: element.offsetTop
  });
}

document.getElementById("button").addEventListener('click', () => {
  scrollTo(document.getElementById("8"));
});

div {
  width: 100%;
  height: 200px;
  background-color: black;
}

div:nth-child(odd) {
  background-color: white;
}

button {
  position: absolute;
  left: 10px;
  top: 10px;
}

<div id="1"></div>
<div id="2"></div>
<div id="3"></div>
<div id="4"></div>
<div id="5"></div>
<div id="6"></div>
<div id="7"></div>
<div id="8"></div>
<div id="9"></div>
<div id="10"></div>
<button id="button">Button</button>

Solution 4 - Javascript

Use this:

let element = document.getElementById("box");

element.scrollIntoView();
element.scrollIntoView(false);
element.scrollIntoView({block: "end"});
element.scrollIntoView({behavior: "instant", block: "end", inline: "nearest"});

DEMO: https://jsfiddle.net/anderpo/x8ucc5ak/1/

Solution 5 - Javascript

This is a pretty old question, but I think it's important to say that nowadays smooth scrolling is supported in CSS, so there's no need for any scripts:

html {
  scroll-behavior: smooth;
}

This property still has no support for Safari or IE/Edge as of 2019, so for a full crossbrowser support, you'll still have to use a script.

Solution 6 - Javascript

CSS3 transitions with a :target selector can give a nice result without any JS hacking. I was just contemplating whether to imlement this but without Jquery it does get a bit messy. See this question for details.

Solution 7 - Javascript

Smooth Scroll behavior with polyfill...

Example:

document.querySelectorAll('a[href^="#"]').addEventListener("click", function(event) {
  event.preventDefault();
  document.querySelector(this.getAttribute("href")).scrollIntoView({ behavior: "smooth" });
});

Repository: https://github.com/iamdustan/smoothscroll

Solution 8 - Javascript

Vanilla js variant using requestAnimationFrame with easings and all browsers supported:

const requestAnimationFrame = window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame;

function scrollTo(to) {
    const start = window.scrollY || window.pageYOffset
    const time = Date.now()
    const duration = Math.abs(start - to) / 3;

    (function step() {
        var dx = Math.min(1, (Date.now() - time) / duration)
        var pos = start + (to - start) * easeOutQuart(dx)

        window.scrollTo(0, pos)

        if (dx < 1) {
            requestAnimationFrame(step)
        }
    })()
}

Any easing supported!

Solution 9 - Javascript

Try this code here:

window.scrollTo({
		top: 0,
		left: 0,
		behavior: 'smooth'
	});

Solution 10 - Javascript

My favorite scroll-to library currently is Zenscroll because of the wide range of features and small size (currently only 3.17kb).

In the future it may make more sense to use the native scrollIntoView functionality, but since it'd have to be polyfilled in most production sites today due to the lack of IE support, I recommend using Zenscroll instead in all cases.

Solution 11 - Javascript

It's upgraded version from @Ian

// Animated scroll with pure JS
// duration constant in ms
const animationDuration = 600;
// scrollable layout
const layout = document.querySelector('main');
const fps = 12;  // in ms per scroll step, less value - smoother animation
function scrollAnimate(elem, style, unit, from, to, time, prop) {
    if (!elem) {
        return;
    }
    var start = new Date().getTime(),
        timer = setInterval(function () {
            var step = Math.min(1, (new Date().getTime() - start) / time);
            var value =  (from + step * (to - from)) + unit;
            if (prop) {
                elem[style] = value;
            } else {
                elem.style[style] = value;
            }
            if (step === 1) {
                clearInterval(timer);
            }
        }, fps);
    if (prop) {
        elem[style] = from + unit;
    } else {
        elem.style[style] = from + unit;
    }
}

function scrollTo(hash) {
    const target = document.getElementById(hash);
    const from = window.location.hash.substring(1) || 'start';
    const offsetFrom = document.getElementById(from).offsetTop;
    const offsetTo = target.offsetTop;
    scrollAnimate(layout,
        "scrollTop", "", offsetFrom, offsetTo, animationDuration, true);
    setTimeout(function () {
      window.location.hash = hash;
    }, animationDuration+25)
};

// add scroll when click on menu items 
var menu_items = document.querySelectorAll('a.mdl-navigation__link');
menu_items.forEach(function (elem) {
    elem.addEventListener("click",
        function (e) {
            e.preventDefault();
            scrollTo(elem.getAttribute('href').substring(1));
        });
});

// scroll when open link with anchor 
window.onload = function () {
    if (window.location.hash) {
        var target = document.getElementById(window.location.hash.substring(1));
        scrollAnimate(layout, "scrollTop", "", 0, target.offsetTop, animationDuration, true);
    }
}

Solution 12 - Javascript

For anyone in 2019, first, you add an event listener

  document.getElementById('id').addEventListener('click', () => scrollTo())

then you target the element and go smoothly to it

function scrollTo() {
    let target = document.getElementById('target');
    target.scrollIntoView({
        behavior: "smooth", 
        block: "end", 
        inline: "nearest"
    })
}

Solution 13 - Javascript

Based on MDN docs for scroll options we can use the following code:

element.scrollTo({
  top: 100,
  left: 100,
  behavior: 'smooth'
});

In fact, the behavior key can accept smooth and auto variables. first for smooth motion and second for a single jump. ‍‍

Solution 14 - Javascript

March 2022

I know this is an old question but wanted to put forward an answer that has simpler ways of doing it in modern days. As of today, almost all the major browsers are compatible with scroll-behavior including Safari with its latest release. Still, you might want to employ fallback methods or just use the javascript approach described in method 2 for compatibility in older browsers.

Method 1: HTML and CSS

You can just do this with

<a href="#target" id="scroll-trigger">Click</a>
.
.
.
<h2 id="target">Target</h2>

and CSS

html {
    scroll-behavior: smooth
} 

Method 2: JavaScript

Or if you have a unique case that needs javascript, go on elaborate with this method.

const scrollTrigger = document.getElementById('scroll-trigger');
const target = document.getElementById('target');

scrollTrigger.addEventListener('click', function (e) {
    window.scroll({
        top: target.offsetTop,
        left:0,
        behavior: 'smooth' });
}, false)

Solution 15 - Javascript

Here is a simple solution in pure JavaScript. It takes advantage of CSS property scroll-behavior: smooth

function scroll_to(id) {       
    document.documentElement.style.scrollBehavior = 'smooth'
    element = document.createElement('a');
    element.setAttribute('href', id)
    element.click();
}

Usage:

Say we have 10 divs:

<div id='df7ds89' class='my_div'>ONE</div>
<div id='sdofo8f' class='my_div'>TWO</div>
<div id='34kj434' class='my_div'>THREE</div>
<div id='gbgfh98' class='my_div'>FOUR</div>
<div id='df89sdd' class='my_div'>FIVE</div>
<div id='34l3j3r' class='my_div'>SIX</div>
<div id='56j5453' class='my_div'>SEVEN</div>
<div id='75j6h4r' class='my_div'>EIGHT</div>
<div id='657kh54' class='my_div'>NINE</div>
<div id='43kjhjh' class='my_div'>TEN</div>

We can scroll to the ID of choice:

scroll_to('#657kh54')

You simply call this function on your click event (e.g. click button then scroll to div #9).

Result:

enter image description here

Of course it looks much smoother in real life.

FIDDLE

Unfortunately, IE and Safari don't support scrollBehavior = 'smooth' as of 2019

enter image description here MDN Web Docs

Solution 16 - Javascript

For a more comprehensive list of methods for smooth scrolling, see my answer here.


To scroll to a certain position in an exact amount of time, window.requestAnimationFrame can be put to use, calculating the appropriate current position each time. setTimeout can be used to a similar effect when requestAnimationFrame is not supported.

/*
   @param pos: the y-position to scroll to (in pixels)
   @param time: the exact amount of time the scrolling will take (in milliseconds)
*/
function scrollToSmoothly(pos, time) {
    var currentPos = window.pageYOffset;
    var start = null;
    if(time == null) time = 500;
    pos = +pos, time = +time;
    window.requestAnimationFrame(function step(currentTime) {
        start = !start ? currentTime : start;
        var progress = currentTime - start;
        if (currentPos < pos) {
            window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos);
        } else {
            window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time));
        }
        if (progress < time) {
            window.requestAnimationFrame(step);
        } else {
            window.scrollTo(0, pos);
        }
    });
}

Demo:

function scrollToSmoothly(pos, time) {
    var currentPos = window.pageYOffset;
    var start = null;
    if(time == null) time = 500;
    pos = +pos, time = +time;
    window.requestAnimationFrame(function step(currentTime) {
        start = !start ? currentTime : start;
        var progress = currentTime - start;
        if (currentPos < pos) {
            window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos);
        } else {
            window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time));
        }
        if (progress < time) {
            window.requestAnimationFrame(step);
        } else {
            window.scrollTo(0, pos);
        }
    });
}

document.getElementById("toElement").addEventListener('click', function(e) {
  var elem = document.querySelector("div");
  scrollToSmoothly(elem.offsetTop);
});
document.getElementById("toTop").addEventListener('click', function(e){
  scrollToSmoothly(0, 700);
});

<button id="toElement">Scroll To Element</button>
<div style="margin: 1000px 0px; text-align: center;">Div element
  <button id="toTop">Scroll back to top</button>
</div>

For more complex cases, the SmoothScroll.js library can be used, which handles smooth scrolling both vertically and horizontally, scrolling inside other container elements, different easing behaviors, scrolling relatively from the current position, and more.

document.getElementById("toElement").addEventListener('click', function(e) {
  smoothScroll({toElement: document.querySelector('div'), duration: 500});
});
document.getElementById("toTop").addEventListener('click', function(e){
  smoothScroll({yPos: 0, duration: 700});
});

<script src="https://cdn.jsdelivr.net/gh/LieutenantPeacock/[email protected]/src/smoothscroll.min.js" integrity="sha384-UdJHYJK9eDBy7vML0TvJGlCpvrJhCuOPGTc7tHbA+jHEgCgjWpPbmMvmd/2bzdXU" crossorigin="anonymous"></script>
<button id="toElement">Scroll To Element</button>
<div style="margin: 1000px 0px; text-align: center;">Div element
  <button id="toTop">Scroll back to top</button>
</div>

Alternatively, you can pass an options object to window.scroll which scrolls to a specific x and y position and window.scrollBy which scrolls a certain amount from the current position:

// Scroll to specific values
// scrollTo is the same
window.scroll({
  top: 2500, 
  left: 0, 
  behavior: 'smooth' 
});

// Scroll certain amounts from current position 
window.scrollBy({ 
  top: 100, // could be negative value
  left: 0, 
  behavior: 'smooth' 
});

Demo:

<button onClick="scrollToDiv()">Scroll To Element</button>
<div style="margin: 500px 0px;">Div</div>
<script>
function scrollToDiv(){
var elem = document.querySelector("div");
window.scroll({
      top: elem.offsetTop, 
      left: 0, 
      behavior: 'smooth' 
});
}
</script>

Modern browsers support the scroll-behavior CSS property, which can be used to make scrolling in the document smooth (without the need for JavaScript). Anchor tags can be used for this by giving the anchor tag a href of # plus the id of the element to scroll to). You can also set the scroll-behavior property for a specific container like a div to make its contents scroll smoothly.

html, body{
  scroll-behavior: smooth;
}

<a href="#elem">Scroll To Element</a>
<div id="elem" style="margin: 500px 0px;">Div</div>

Solution 17 - Javascript

Without jQuery

const links = document.querySelectorAll('header nav ul a')

for (const link of links) {
  link.onclick = function clickHandler(e) {
    e.preventDefault()
    const href = this.getAttribute('href')
    document.querySelector(href).scrollIntoView({ behavior: 'smooth' })
  }
}

<header>
  <!-- NavBar -->
  <nav>
    <ul>
      <li><a href="#team">Team</a></li>
      <li><a href="#contact">Contact</a></li>
      <li><a href="#about">About</a></li>
    </ul>
  </nav>
</header>

<!-- ----------- Team ----------------------- -->
<div id="team">
  <h2>Team</h2>
</div>

<!-- ----------- Contact ----------------------- -->
<div id="contact">
  <h2>Contact</h2>
</div>

<!-- ----------- About ----------------------- -->
<div id="about">
  <h2>About</h2>
</div>

  body {
    background-color: black;
    height:7000px
  }

  header {
    margin-top: 1.3rem;
    margin-bottom: 25rem;
    display: flex;
    justify-content: center;
    align-items: center;
  }

  nav ul {
    display: flex;
  }

  nav ul li {
    all: unset;
    margin: 2rem;
    cursor: pointer;
  }

  nav ul li a {
    all: unset;
    font: bold 1.8rem robto;
    color: white;
    letter-spacing: 1px;
    cursor: pointer;
    padding-top: 3rem;
    padding-bottom: 2rem;
  }

  #team,
  #contact,
  #about {
    background-color: #e2df0d;
    width: 100%;
    height: 35rem;
    display: flex;
    justify-content: center;
    align-items: center;
    color: black;
    font: bold 4rem roboto;
    letter-spacing: 6.2px;
    margin-top: 70rem;

  }

Or with just CSS, but it's not supported in all browsers yet

html {scroll-behavior: smooth}

Solution 18 - Javascript

If you want to set all of your deep links # to scroll smoothly you can do this:

const allLinks = document.querySelectorAll('a[href^="#"]')
allLinks.forEach(link => {

  const 
    targetSelector = link.getAttribute('href'),
    target = document.querySelector(targetSelector)

  if (target) {
    link.addEventListener('click', function(e) {

    e.preventDefault()

    const top = target.offsetTop // consider decreasing your main nav's height from this number

    window.scroll({
      behavior: 'smooth',
      left: 0,
      top: top
    });

  })
}
})

An example code to consider also your main nav's height (this code goes where top const is declared):

const 
  mainHeader = document.querySelector('header#masthead'), //change to your correct main nav selector
  mainHeaderHeight = mainHeader.offsetHeight,
  // now calculate top like this:
  top = target.offsetTop - mainHeaderHeight 

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondrozdzynskiView Question on Stackoverflow
Solution 1 - JavascriptTejas Anil ShahView Answer on Stackoverflow
Solution 2 - JavascriptIanView Answer on Stackoverflow
Solution 3 - JavascriptasvetlyView Answer on Stackoverflow
Solution 4 - JavascriptAnderpoView Answer on Stackoverflow
Solution 5 - JavascriptAlexandre AimbiréView Answer on Stackoverflow
Solution 6 - JavascriptLouis MaddoxView Answer on Stackoverflow
Solution 7 - JavascriptillvartView Answer on Stackoverflow
Solution 8 - JavascriptOleksandr KozlovView Answer on Stackoverflow
Solution 9 - JavascriptAlberto JuniorView Answer on Stackoverflow
Solution 10 - JavascriptZach SaucierView Answer on Stackoverflow
Solution 11 - JavascriptYevhenii DehtiarView Answer on Stackoverflow
Solution 12 - JavascriptFrançois PIQUARDView Answer on Stackoverflow
Solution 13 - JavascriptAmerllicAView Answer on Stackoverflow
Solution 14 - JavascriptNipunaView Answer on Stackoverflow
Solution 15 - JavascriptCyberneticView Answer on Stackoverflow
Solution 16 - JavascriptUnmitigatedView Answer on Stackoverflow
Solution 17 - JavascriptAhmad MoghaziView Answer on Stackoverflow
Solution 18 - JavascriptNadavView Answer on Stackoverflow