A bug was brought to my attention the other day on a page where I was using jQuery to animate the scroll position on the page when a certain link was clicked. This type of action is commonly used to help a user quickly get back to the top of a lengthy page after scrolling down. (It isn't always animated, but I like to add in the animation when I can because it seems less disorienting; the page slides instead of just jumping straight to the new position. The animation doesn't have any effect on this particular bug so I will leave it out of this post.)
The code I was using to create this effect looked something like this:
$('body').scrollTop(50);. Seems pretty straightforward and has the desired effect in Google Chrome. However, this will not work in Firefox or IE (that was the bug). Hmmm, ok. Let's try
$('html').scrollTop(50);. Now this works in Firefox and IE, but not Chrome.
Time to do some research. I found this question on Stack Overflow (the question is a little dated, but the answers are somewhat recent). Apparently Webkit browsers place the overflow at the body level while other browsers (like Firefox and IE) place it at the html level, which is why they respond differently to the selectors I was trying to use.
There were quite a few suggested solutions within that discussion, so I'll walk through a few that I tried and explain the solution I ended up going with.
Specify both body and html as selectors
This is pretty close. The drawback to this method though, as mentioned in one of the Stack Overflow comments, is that the function is executed twice. This is not too big of a deal in this example, but could become a problem if you do something more extensive in addition to scrolling (such as making an ajax call). Not feeling great about this solution.
Use document or window as the selector
Use jQuery.browser.webkit to detect whether or not a Webkit browser is being used.
$(jQuery.browser.webkit ? 'body' : 'html').scrollTop(50);
$.browser is deprecated/removed and will not work with the latest jQuery versions (This will actually work with versions of jQuery below 2.x if you also include the jQuery migrate plugin, but should be avoided because it's deprecated).
The $.browser property is deprecated in jQuery 1.3, and its functionality may be moved to a team-supported plugin in a future release of jQuery.
Because $.browser uses navigator.userAgent to determine the platform, it is vulnerable to spoofing by the user or misrepresentation by the browser itself. It is always best to avoid browser-specific code entirely where possible. Instead of relying on $.browser it's better to use libraries like Modernizr. http://api.jquery.com/jquery.browser/
Ah yes, Modernizr. What a great idea.
Final Solution: Use feature detection with Modernizr.
var selector = Modernizr.testProp('webkitAppearance') ? 'body' : 'html'; $(selector).scrollTop(50);
I don't know if there is a detectable property associated with this specific issue, so I decided to check against the
-webkit-appearance property. I'm also not sure if there is a standard/preferred default property to check against when trying to detect Webkit in general, but support with the -webkit prefix for appearance looks pretty solid.
You can check out my full example on CodePen.