Skip to content

Instantly share code, notes, and snippets.

@anisur3036
Created May 7, 2018 06:43
Show Gist options
  • Save anisur3036/9d97d55790d46ba9bbe0febb3f9c4c19 to your computer and use it in GitHub Desktop.
Save anisur3036/9d97d55790d46ba9bbe0febb3f9c4c19 to your computer and use it in GitHub Desktop.
Smooth scrolling to anchor with pure javascript
<div class="container">
<div class="filler anchor" id="anchor1">anchor1</div>
<div class="links">
<a id="anchor1Link" href="#anchor1">Anchor 1</a>
<a id="anchor2Link" href="#anchor2">Anchor 2</a>
<a id="anchor3Link" href="#anchor3">Anchor 3</a>
<a id="anchor4Link" href="#anchor4">Anchor 4</a>
</div>
<div class="longText">
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p id="anchor2" class="anchor">anchor2 : This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p id="anchor3" class="anchor">anchor3 : This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p>This is a line, and there will be more after me.</p>
<p id="anchor4" class="anchor">anchor4 : This is a line, and there will be more after me.</p>
</div>
<div class="links">
<a id="anchor1Link2" href="#anchor1">Anchor 1</a>
<a id="anchor2Link2" href="#anchor2">Anchor 2</a>
<a id="anchor3Link2" href="#anchor3">Anchor 3</a>
<a id="anchor4Link2" href="#anchor4">Anchor 4</a>
</div>
<div class="filler"></div>
</div>
(function() {
let d = document;
function init() {
//Links
let anchor1Link = d.getElementById('anchor1Link');
let anchor2Link = d.getElementById('anchor2Link');
let anchor3Link = d.getElementById('anchor3Link');
let anchor4Link = d.getElementById('anchor4Link');
let anchor1Link2 = d.getElementById('anchor1Link2');
let anchor2Link2 = d.getElementById('anchor2Link2');
let anchor3Link2 = d.getElementById('anchor3Link2');
let anchor4Link2 = d.getElementById('anchor4Link2');
//Anchors
let anchor1 = d.getElementById('anchor1');
let anchor2 = d.getElementById('anchor2');
let anchor3 = d.getElementById('anchor3');
let anchor4 = d.getElementById('anchor4');
anchor1Link.addEventListener('click', (e) => { scrollTo(anchor1, e) }, false);
anchor1Link2.addEventListener('click', (e) => { scrollTo(anchor1, e) }, false);
anchor2Link.addEventListener('click', (e) => { scrollTo(anchor2, e) }, false);
anchor2Link2.addEventListener('click', (e) => { scrollTo(anchor2, e) }, false);
// anchor2Link.onclick = function() { scrollToSimple(document.documentElement, 500, 3000); }
// anchor2Link2.onclick = function() { scrollToSimple(document.documentElement, 0, 3000); }
anchor3Link.addEventListener('click', (e) => { scrollTo(anchor3, e) }, false);
anchor3Link2.addEventListener('click', (e) => { scrollTo(anchor3, e) }, false);
anchor4Link.addEventListener('click', (e) => { scrollTo(anchor4.offsetTop, e) }, false);
anchor4Link2.addEventListener('click', (e) => { scrollTo(anchor4.offsetTop, e) }, false);
console.log(anchor2); //DEBUG
console.log('anchor1: '+scrollTopValue(anchor1)+' / '+offsetTopValue(anchor1)); //DEBUG
console.log('anchor2: '+scrollTopValue(anchor2)+' / '+offsetTopValue(anchor2)); //DEBUG
console.log('anchor3: '+scrollTopValue(anchor3)+' / '+offsetTopValue(anchor3)); //DEBUG
console.log('anchor4: '+scrollTopValue(anchor4)+' / '+offsetTopValue(anchor4)); //DEBUG
// d.addEventListener('scroll', (e) => { console.log(e) }, false); //DEBUG
console.log('App loaded. Have fun!');
}
function scrollTopValue(domElement) { //DEBUG
return 'scrollTopValue:', domElement.scrollTop;
}
function offsetTopValue(domElement) { //DEBUG
return 'offsetTopValue:', domElement.offsetTop;
}
/*function scrollToSimple(element, to, duration) { //FIXME finish this
if (duration < 0) return;
var difference = to - element.offsetTop;
var perTick = difference / duration * 10;
console.log('perTick', perTick); //DEBUG
setTimeout(function() {
console.log('element.scrollTop:', element.scrollTop); //DEBUG
element.scrollTop += perTick;
console.log('element.scrollTop:', element.scrollTop); //DEBUG
scrollTo(element, to, duration - 10);
}, 10);
}*/
//cf. https://gist.github.com/james2doyle/5694700
// requestAnimationFrame for Smart Animating https://goo.gl/sx5sts
var requestAnimFrame = (function() {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function scrollTo(to, callback, duration = 1500) { //FIXME this always starts from '0', instead of the clicked element offsetTop -> This is because the position is calculated for the main <html> element, not the <iframe>'s <html> tag
/*console.log('from:', from); //DEBUG
// console.log('from.clientY:', from.clientY); //DEBUG
// console.log('from.target.offsetTop:', from.target.offsetTop); //DEBUG
// console.log('position():', document.documentElement.offsetTop || document.body.parentNode.offsetTop || document.body.offsetTop); //DEBUG
// console.log('document.documentElement:', document.documentElement); //DEBUG
// console.log('document.body:', document.body); //DEBUG
let start;
if (isMouseEvent(from)) { //FIXME : the scroll starts at the link, not where the screen really is : fix that
// start = from.target.offsetTop;
start = from.pageY; //FIXME
}
else {
start = from;
}*/
if (isDomElement(to)) {
// console.log('this is an element:', to); //DEBUG
to = to.offsetTop;
}
/*else {
// console.log('this is NOT an element:', to); //DEBUG
}*/
// because it's so fucking difficult to detect the scrolling element, just move them all
function move(amount) {
// document.scrollingElement.scrollTop = amount; //FIXME Test that
document.documentElement.scrollTop = amount;
document.body.parentNode.scrollTop = amount;
document.body.scrollTop = amount;
}
function position() {
return document.documentElement.offsetTop || document.body.parentNode.offsetTop || document.body.offsetTop;
}
var start = position(),
change = to - start,
currentTime = 0,
increment = 20;
console.log('start:', start); //DEBUG
console.log('to:', to); //DEBUG
console.log('change:', change); //DEBUG
var animateScroll = function() {
// increment the time
currentTime += increment;
// find the value with the quadratic in-out easing function
var val = Math.easeInOutQuad(currentTime, start, change, duration);
// move the document.body
move(val);
// do the animation unless its over
if (currentTime < duration) {
requestAnimFrame(animateScroll);
}
else {
if (callback && typeof(callback) === 'function') {
// the animation is done so lets callback
callback();
}
}
};
animateScroll();
}
init();
})();
//-------------------- Unimportant js functions --------------------
// easing functions https://goo.gl/5HLl8
//t = current time
//b = start value
//c = change in value
//d = duration
Math.easeInOutQuad = function(t, b, c, d) {
t /= d / 2;
if (t < 1) {
return c / 2 * t * t + b
}
t--;
return -c / 2 * (t * (t - 2) - 1) + b;
};
Math.easeInCubic = function(t, b, c, d) {
var tc = (t /= d) * t * t;
return b + c * (tc);
};
Math.inOutQuintic = function(t, b, c, d) {
var ts = (t /= d) * t,
tc = ts * t;
return b + c * (6 * tc * ts + -15 * ts * ts + 10 * tc);
};
function isDomElement(obj) {
return obj instanceof Element;
}
function isMouseEvent(obj) {
return obj instanceof MouseEvent;
}
function findScrollingElement(element) { //FIXME Test this too
do {
if (element.clientHeight < element.scrollHeight || element.clientWidth < element.scrollWidth) {
return element;
}
} while (element = element.parentNode);
}
.links {
// position: absolute;
// top: 0;
// left: 50%;
// transform: translate(-50%, 0);
margin-top: 0.5rem;
margin-bottom: 2rem;
a {
font-size: 1.4rem;
color: lightblue;
text-decoration: none;
transition: color .5s ease, border-bottom .5s ease;
border-bottom: 2px solid transparent;
&:hover {
color: yellow;
border-bottom: 2px solid yellow;
}
&:not(:last-of-type) {
margin-right: 2rem;
}
}
}
.longText {
& > p:last-of-type:after {
content : '...or not ;)';
}
}
.anchor {
color: lime;
font-weight: bold;
}
p {
margin: 0;
text-align: center;
}
//-------------------- Unimportant css rules --------------------
$transitionDuration: 0.3s;
.container {
// height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.filler {
background-color : #0B3553;
border: 1px solid #022238;
opacity : 0.80;
height: 25vh;
width: 99vw; //FIXME: 100vw make a scrollbar appear :'(
}
body {
background: #333; //#022238
color: white;
font-family: "Open sans", sans-serif;
font-weight: 100;
font-size: 1rem;
}
a.button {
// color: white;
color: yellow;
text-decoration: none;
transition: color $transitionDuration ease;
&:focus {
outline: none;
}
&:hover {
// color: deeppink;
color: lime;
}
}
.button2 {
background-color : deeppink;
color : white;
border : 1px solid red;
border-radius : 2px;
height : 30px;
cursor : pointer;
outline : none;
&:focus, &:active {
outline : none;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment