Smooth scroll anchor links WITHOUT jQuery

℡╲_俬逩灬. 提交于 2019-11-27 06:29:37
Ian

Using the function from here: JavaScript animation and modifying it to modify a property (not only a style's property), you can try something like this:

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);
};

DEMO: https://jsfiddle.net/zpu16nen/

Make sure you size the window small enough so there's actually a scrollbar and can scroll to the 5th div.

And no, it didn't require the recreation of 25% of jQuery.

This would obviously needly highly modified depending on what your question actually means (like when the window hash changes, or something like that).

Note that with jQuery, it's as easy as:

$(document).ready(function () {
    $("html, body").animate({
        scrollTop: $("#div5").offset().top
    }, 2000);
});

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

Just saying...

Tejas Shah

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.

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>

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/

Louis Maddox

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.

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!

Pure lightweight javascript library: smooth-scroll on github

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.

Alberto Junior

Try this code here:

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

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

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);
    }
}

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:

Of course it looks much smoother in real life.

FIDDLE

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

MDN Web Docs

François PIQUARD

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"
    })
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!