Skip to content

Instantly share code, notes, and snippets.

@bootsified
Last active June 12, 2019 21:25
Show Gist options
  • Save bootsified/71472b4df5d38ea34e3f936fcba4c713 to your computer and use it in GitHub Desktop.
Save bootsified/71472b4df5d38ea34e3f936fcba4c713 to your computer and use it in GitHub Desktop.
Assign links to scroll to content within page.
/*///////////////////////////////////////////////////////////////
SCROLL TO ANCHOR
Using your site's onLoad function, initialize the script:
`ScrollToAnchor.init();`
Any link with a hash href (e.g. '#myElement') will scroll the page
to the link position. To disable the scrolling for a link, give it
the 'no-scroll' class:
`<a href="#myElement" class="no-scroll">Click me</a>`
To manually scroll the page, call:
`scrollPage(target, padding, duration, easing, callback);`
Example:
`ScrollToAnchor.scrollPage('#myElement', 0, 750, 'easeInOutCubic', myCallbackFunction);`
Notes:
- The 'padding' parameter is the amount of extra space (pixels)
above the element when scrolling completes (default 0).
- Default duration is 750 (milliseconds).
- For easing functions, see Easing object below.
Default 'easeInOutCubic'.
///////////////////////////////////////////////////////////////*/
var ctaRafId,
ScrollToAnchor = {
init: function() {
this.bindUIActions();
},
bindUIActions: function() {
var elems = document.querySelectorAll('a[href*="#"]:not(.no-scroll)');
if (elems.length) {
elems.forEach(function(elem) {
elem.addEventListener('click', ScrollToAnchor.onClick);
});
}
},
getHeaderHeight: function() {
var headHeight;
headHeight = document.querySelector('.site-header').offsetHeight + 20;
return headHeight;
},
onClick: function(e) {
try {
e.preventDefault();
var targetId = this.getAttribute('href'),
targetPad = this.getAttribute('data-scroll-pad'),
pad = 0;
if (typeof targetPad !== typeof null && targetPad !== '') {
pad = parseInt(targetPad);
}
// console.debug('targetId: ' + targetId);
// console.debug('elem: ' + document.querySelector(targetId));
if (targetId != '#' && targetId != '#0' && document.querySelector(targetId)) {
ScrollToAnchor.scrollPage(targetId, pad);
document.querySelector('html').classList.remove('menu-open');
}
} catch (error) {
console.debug(error.message);
window.location = this.getAttribute('href');
}
},
scrollPage: function(trgt, pad, duration, easing, callback) {
// console.debug('pad: ' + pad);
if (typeof pad === 'undefined') {
pad = 0;
}
if (typeof duration === 'undefined') {
duration = 750;
}
if (typeof easing === 'undefined') {
easing = 'easeInOutCubic';
}
try {
var destination = document.querySelector(trgt);
var start = window.pageYOffset;
var startTime = 'now' in window.performance ? performance.now() : new Date().getTime();
var documentHeight = Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);
var windowHeight = window.innerHeight || document.documentElement.clientHeight || document.getElementsByTagName('body')[0].clientHeight;
var windowWidth = window.innerWidth || document.documentElement.clientWidth || document.getElementsByTagName('body')[0].clientWidth;
var headerHeight = ScrollToAnchor.getHeaderHeight();
// TODO: For some reason, `offsetTop` doesn't work for the grid elements when stacked on mobile.
// var offsetTop = destination.offsetTop;
var offsetTop = $(destination).offset().top; // TODO: Convert to vanilla js
var currentScroll = window.scrollY + headerHeight;
if (pad < 1 && windowWidth >= 840) {
if (offsetTop > currentScroll) {
pad = 50;
} else {
pad = headerHeight;
}
} else {
pad = headerHeight;
}
var destinationOffset = typeof destination === 'number' ? destination : offsetTop - pad;
var destinationOffsetToScroll = Math.round(documentHeight - destinationOffset < windowHeight ? documentHeight - windowHeight : destinationOffset);
// console.debug('----------------');
console.debug('pad: ' + pad);
// console.debug('start: ' + start);
// console.debug('startTime: ' + startTime);
// console.debug('documentHeight: ' + documentHeight);
// console.debug('windowHeight: ' + windowHeight);
// console.debug('offsetTop: ' + offsetTop);
// console.debug('currentScroll: ' + currentScroll);
// console.debug('destination.offsetTop: ' + destination.offsetTop);
// console.debug('destinationOffset: ' + destinationOffset);
// console.debug('destinationOffsetToScroll: ' + destinationOffsetToScroll);
// console.debug('----------------');
if ('requestAnimationFrame' in window === false) {
window.scroll(0, destinationOffsetToScroll);
if (callback) {
callback();
}
return;
}
function scroll() {
var now = 'now' in window.performance ? performance.now() : new Date().getTime();
var time = Math.min(1, ((now - startTime) / duration));
var timeFunction = Easings[easing](time);
window.scroll(0, Math.ceil((timeFunction * (destinationOffsetToScroll - start)) + start));
if (window.pageYOffset === destinationOffsetToScroll) {
if (callback) {
callback();
}
return;
}
ctaRafId = requestAnimationFrame(scroll);
}
// scroll();
ctaRafId = requestAnimationFrame(scroll);
setTimeout(function() {
cancelAnimationFrame(ctaRafId);
}, 1000);
} catch (error) {
console.log('Caught error: ' + error.message)
}
},
destroy: function() {
var elems = document.querySelectorAll('a[href*="#"]:not(.no-scroll)');
elems.forEach(function(elem) {
elem.removeEventListener('click', ScrollToAnchor.onClick);
});
}
};
var Easings = {
linear: function(t) {
return t;
},
easeInQuad: function(t) {
return t * t;
},
easeOutQuad: function(t) {
return t * (2 - t);
},
easeInOutQuad: function(t) {
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
},
easeInCubic: function(t) {
return t * t * t;
},
easeOutCubic: function(t) {
return (--t) * t * t + 1;
},
easeInOutCubic: function(t) {
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
},
easeInQuart: function(t) {
return t * t * t * t;
},
easeOutQuart: function(t) {
return 1 - (--t) * t * t * t;
},
easeInOutQuart: function(t) {
return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t;
},
easeInQuint: function(t) {
return t * t * t * t * t;
},
easeOutQuint: function(t) {
return 1 + (--t) * t * t * t * t;
},
easeInOutQuint: function(t) {
return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment