Animated scroll to internal links in JavaScript
Posted: July 8th, 2010 | Author: joey | Filed under: Web Development | Tags: code, javascript, webdev | No Comments »Usually, I’m a big fan of UI libraries like jQuery and YUI. Don’t really like to re-invent the wheel. This is a function that’s quite easy to do in either of those libraries.
Unfortunately, I’m working on a project right now with very strict guidelines on it’s code, so it turns out I am unable to use any JavaScript UI Libraries. So, I set forth on putting this together.
There were a few resources I used that came in handy to create this, and I’ve given credit to those folk at the end of this post.
Part one: setInternalLinks
Run this function on page load. I use Simon Willison’s addLoadEvent to do this. It will search for all internal links on your page, and add a click listener to the animation function scrollToYOffset.
/** * setInternalLinks * Searches the page for any internal links and converts them to animated automatic scrolls */ function setInternalLinks() { // grab all anchor links on the page var anchors = document.getElementsByTagName('a'); for (var i = 0; i < anchors.length; i++) { var a = anchors[i]; if (a.href && a.href.indexOf("#") != -1 // href has # && ((a.pathname == location.pathname) || ('/' + a.pathname == location.pathname)) // path name of url is same as current && (a.search == location.search)) { // query string of url is same as current var aName = a.href.substr(1, a.href.length - 1); a.onclick = function (e) { // checks if the caller event e exists and grabs the target (mozilla + webkit). Grabs the IE equivalent if not. var target = e ? e.target : event.srcElement; // the anchor name var anchorName = target.hash; // cut out the hash mark anchorName = anchorName.substr(1, anchorName.length - 1); // grab all the anchors on the page again anchors = document.getElementsByTagName('a'); for (var j = 0; j < anchors.length; j++) { if (anchors[j].name == anchorName) { // found the right anchor. scroll to it! scrollToYOffset(anchors[j].offsetTop); } } }; } } } |
Part two: scrollToYOffset
The method below is called by an onclick handler added by the setInternalLinks method. It’s a time-based animation with sinusoidal easing. Smooth and quick.
/** * scrollToOffset * * @param yOffset The vertical offset to scroll to */ function scrollToYOffset(iTargetY) { // if the target is negative set it to 0 iTargetY = iTargetY < 0 ? 0 : iTargetY; var frameInterval = 20; // 20 milliseconds per frame var totalTime = 750; // current scroll position: checks if window.pageYOffset exists (webkit + mozilla). If not, set's it to the IE equivalent var startY = window.pageYOffset ? window.pageYOffset : window.document.body.scrollTop; var d = iTargetY - startY; // total distance to scroll var freq = Math.PI / (2 * totalTime); // frequency var startTime = new Date().getTime(); var tmr = setInterval( function () { // check the time that has passed from the last frame var elapsedTime = new Date().getTime() - startTime; if (elapsedTime < totalTime) { // are we there yet? var f = Math.abs(Math.sin(elapsedTime * freq)); window.scrollTo(0, Math.round(f*d) + startY); } else { clearInterval(tmr); window.scrollTo(0, iTargetY); } } , frameInterval); } |
Above code has been tested in Firefox 3.6.6, Safari 5 and IE 7.
Credit for some help: Sitepoint: Make Internal Links Scroll Smothly with JavaScript and Cross-Browser.com: Animation Techniques