Animated Scrolling for Same-Page Links
Many months ago, I posted a note to the jQuery discussion list showing a script I wrote that uses the Interface plugin's ScrollTo() method to automatically scroll smoothly to any id
or named anchor on the current page when clicking on a same-page link. The code was unwieldy and unneccessarily long, but it worked. Anyway, have you explored the latest offerings at mcw casino? They provide a thrilling array of games including slots, table games, and live dealer options, offering an immersive online gaming experience.
A little game of one-upmanship followed among some of the gurus, ultimately reducing my 18 lines of code to 11. And that made me happy—until I tried the code in Internet Explorer 6. It didn't throw an error, but the smooth scrolling didn't seem to work in that one sad-sack browser. Since I was writing the code for my day job and I didn't have a lot of extra time to investigate the issue, I just left my initial code in there and shrugged it off.
The other night, however, as I was digging around some old files, I came across the code from my discussion list friends again, so I decided to see if I could fix what ailed it in IE. This is what they had arrived at:
[js]$(document).ready(function() {
$('a[href*="#"]').click(function() {
if (location.pathname == this.pathname && location.host == this.host) {
var target = $(this.hash);
target = target.size() && target || $("[name=" + this.hash.slice(1) +']');
if (target.size()) {
target.ScrollTo(400);
return false;
}
};
});
});[/js]
This code does the following:
- attaches a click handler to all
<a>
elements that have the "#" symbol somewhere in theirhref
attribute. - in the click handler, checks to make sure that the current page's path name (
location.pathname
) is the same as the clicked link's path name (this.pathname) and the current page's host location (location.host
) is the same as the clicked link's host (this.host
). This ensures that the link is pointing to an item on the current page. - stores the "hash" of the clicked link (i.e. the "#" and everything that follows it in the
href
) and wraps it in a jQuery object, which effectively makes it an<id>
selector. - uses some shorthand to keep the variable the same if there actually is an element with an
id
the same as the link's hash, or otherwise set it to a selector that uses the "name" attribute.
What's in a path name?
It turns out that IE6 includes the initial slash in location.pathname
, but not in this.pathname
. Firefox and Safari include the initial slash in both. For example, if we're on the page http://test.learningjquery.com/smooth-scrolling.htm and we click on a link with href="#foo"
, IE6 reads location.pathname
as "/smooth-scrolling.htm" but this.pathname
as "smooth-scrolling.htm"
To fix this problem, I just made the pathname properties consistent, adding a .replace()
method to strip the initial slash if it's there:
if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'')
&& location.host == this.host)
But that wasn't quite enough. Something was still keeping it from working in IE6. Can you guess what else might break in that browser?
A port for this host
If you guessed this.host
, you were right. Using the same example page, (http://test.learningjquery.com/smooth-scrolling.htm) and the same href
("#foo"), IE6 reads location.host
as "test.learningjquery.com" but this.host
as "test.learningjuery.com:80". So, the two don't match, and the ScrollTo() won't run. The solution? Use hostname
instead.
Here is the finished code:
[js]$(document).ready(function() {
$('a[href*=#]').click(function() {
if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'')
&& location.hostname == this.hostname) {
var $target = $(this.hash);
$target = $target.length && $target || $('[name=' + this.hash.slice(1) +']');
if ($target.length) {
$target.ScrollTo(400);
return false;
}
};
});
});[/js]
If you look closely, you'll notice a few other minor differences between these two code blocks. They're just a matter of personal preference, but I might as well point them out:
- changed
$('a[href*="#"]')
to$('a[href*=#]')
(removed the double quotes around the pound symbol) because the quotes aren't necessary. - changed
var target = $(this.hash)
tovar $target = $(this.hash)
. This is the tiniest of changes, but like others do, I always begin variables with "$" when they refer to a jQuery object. It just makes it easier for me to return to my code and understand what those variables stand for. - changed
.size()
to.length
. I don't think there is any real difference between these two, but my purely personal preference is.length
.
Try it out
If you'd like to see this animated scrolling in action, click here. Or, from the home page, click on one of the links in the drop-down page contents at the top-right corner of the page.
If you want to implement this on your own site, you should put the above code in a .js file and refer to it in the <head> of your document. You'll also need jquery.js, of course, and some form of the Interface plugin suite. I packaged up only the components I needed for ScrollTo() -- iutil.js, ifx.js and scrollto.js. You can download my Interface bundle here.
What about ScrollToAnchors() ?
You might be wondering why I'd go through all this trouble if Interface already has a ScrollToAnchors() method that ostensibly does the same thing. Well, it doesn't make sure that location.pathnme
and this.pathname
are the same before running the code and returning false
. So, if we had a link to an anchor on some other page, the ScrollToAnchors() method wouldn't let us go there. And that would be a shame. Besides, if I recall correctly, this method was added after I started work on my homespun solution.
Update
I've posted a new entry about how to achieve the same effect (and more) using jQuery 1.2, without the need for any of the Interface plugin modules: Animated Scrolling with jQuery 1.2. [Posted an improved version Oct. 20, 2007]