views:

3518

answers:

7

I've got a simple setup to allow a "help"-style window to be loaded and scrolled to a particular point on the page. More or less the code looks like this:

var target = /* code */;
target.offsetParent().scrollTop(target.offset().top - fudgeValue);

The target of the scroll and the fudge value are determined by a couple of hints dropped on the page, and I'm having no problems with that part of this mechanism anywhere. In Firefox and IE8, the above code works exactly like I want: the scrolled box (in this case, the page body) correctly scrolls the contained stuff to the right point in the window when it's told to do so.

In Chrome and Safari, however, the call to scrollTop() apparently does nothing at all. All the numbers are OK, and the target refers to the right thing (and the offsetParent() is indeed the body element), but nothing at all happens. As far as I can tell from googling around, this is supposed to work. Is there something funny about the renderer under Safari and Chrome?

This is jQuery 1.3.2 if that matters.

Test page: http://gutfullofbeer.net/scrolltop.html

+1  A: 

Which element is the offsetParent of another is not well-specified and may vary across browsers. It is not guaranteed to the be the scrollable parent you are looking for.

The body itself also shouldn't be the page's main scrollable element. It only is in Quirks Mode, which in general you would want to avoid.

The offsetTop​/​offsetLeft​/​offsetParent measurements aren't terribly useful by themselves, they're only really reliable when you use them in a loop to get the total page-relative co-ordinates (as position() in jQuery does). You should know which is the element you want to scroll and find out the difference in page co-ordinates between that and the descendant target to find out how much to scroll it by.

Or if it's always the page itself you're talking about scrolling, just use a location.href= '#'+target.id navigation instead.

bobince
That page is not rendering in quirks mode. The offsetParent is indeed the body element in all the browsers.Under Safari and Chrome, the page doesn't scroll **at all**. In other words, though the offset numbers come out more or less the same as they do in IE8 and Firefox, nothing at all happens in the call to scrollTop().
Pointy
Also, I can't just use something simple like asking for an element in the scrolled content to "scrollIntoView()" because of the header panel that lies over the top of the content.
Pointy
A: 

There is a bug in Chrome (not in Safari at the time we checked) that gives unexpected results in Javascript's various width and height measurements when opening tabs in the background (bug details here) - we logged the bug in June and it's remained unresolved since.

It's possible you've encountered the bug in what you're attempting to do.

Ross Duggan
+2  A: 

Yeah, there appears to be a bug in Chrome when it comes to modifying the body, trying to make it into an offsetParent. As a work-around, I suggest you simply add another div to wrap the #content div, and make that scroll:

html, body { height: 100%; padding: 0; } 
html { width: 100%; background-color: #222; overflow: hidden; margin: 0; } 
body 
{ 
   width: 40em; margin: 0px auto; /* narrow center column layout */
   background-color: white; 
   position: relative; /* allow positioning children relative to this element */
} 
#scrollContainer /* wraps #content, scrolls */
{ 
  overflow: auto; /* scroll! */
  position:absolute; /* make offsetParent */
  top: 0; height: 100%; width: 100%; /* fill parent */
} 
#header 
{ 
  position: absolute; 
  top: 0px; height: 50px; width: 38.5em; 
  background-color: white; 
  z-index: 1; /* sit above #content in final layout */
} 
#content { padding: 5px 14px 50px 5px;  }

Tested in FF 3.5.5, Chrome 3.0.195.33, IE8
Live demonstration

Shog9
Thanks, yes that's what I eventually worked out (mostly just as a "gee I wonder if this'd help" test). I made the container "position: relative" but otherwise it's pretty much exactly what you suggest.
Pointy
I had another problem where I was trying to use animate to move the scrolltop. In my case, it turns out that you have to add document.documentElement.scrollTop to document.body.scrollTop. Both will not have a value in all browsers, so together they equal your target. Thought I'd put that in there for anyone else who found this issue.
NateDSaint
+8  A: 

I was having this problem in safari and chrome (Mac) and discovered that .scrollTop would work on $("body") but not $("html, body"), FF and IE however works the other way round. A simple browser detect fixes the issue:

if($.browser.safari){ bodyelem = $("body") } else{ bodyelem = $("html,body") } bodyelem.scrollTop(100)

The jquery browser value for chrome is safari so you only need to do a detect on that

Hope this helps someone

Carl
@Carl - That really helped me out, thanks.
James
Just tested in FF 3.6, Safari 5, Chrome 6, Opera 10 and IE7. Bravo!
FFish
A: 

the browser support status is that:
IE8、Firefox、opera : $("html")
Chorme、safari : $("body")

so :
if($.browser.safari){ bodyelem = $("body") } else{ bodyelem = $("html") } bodyelem.animate({scrollTop:0},500);

than's OK

pengkai
+1  A: 

Works for Safari, Firefox, and IE7 (haven't tried IE8). Simple test:

<button onclick='$("body,html").scrollTop(0);'> Top </button>

<button onclick='$("body,html").scrollTop(100);'> Middle </button>

<button onclick='$("body,html").scrollTop(250);'> Bottom </button>

Most examples use either one or both, but in reverse order (i.e., "html,body").

Cheers.

(And semantic purists out there, don't bust my chops -- I've been looking for this for weeks, this is a simple example, that validates XHTML strict. Feel free to create 27 layers of abstraction and event binding bloat for your OCD peace of mind. Just please give due credit, since the folks in the jQuery forums, SO, and the G couldn't cough up the goods. Peace out.)

GeekDad
A: 

$(window).scrollTop(); works in all browsers I believe.

not in FF and Opera
FFish