简体   繁体   中英

jQuery animate scrolltop on Opera bug

Has anyone tried using

$(“html, body”).animate({scrollTop:0}, 'slow');

on Opera browser?

It does a weird effect especially if you scroll on a long page, it seems like the page go first to the top and then it scroll down to the right point. It is a weird disturbing effect...

Is there any workaround to fix it? thanks

The attribute was not defined properly in the past. It was introduced by IE, I think, then reverse engineered to be implemented by different user agents. It has been since described in CSSOM (still a working draft). As of today, there is still a bug indeed in Opera which is being in the process to be fixed.

## Possible hack.

A solution will be

$(window.opera?'html':'html, body').animate({ 
  scrollTop:0}, 'slow' 
);

Be careful because if Opera fixes it at a point, the code is likely to behave strangely.

Why?

  • In Firefox and IE quirks mode, you have to set the property on the "body" to make the page scroll, while it is ignored if you set it on the "html".
  • In Firefox and IE standards mode, you have to set the property on the "html" to make the page scroll, while it is ignored if you set it on the "body".
  • In Safari and Chrome, in either mode, you have to set the property on the "body" to make the page scroll, while it is ignored if you set it on the "html".

Since the page is in standards mode, they have to set it on both the "html" and "body, or it won't work in Safari/Chrome.

Now here's the bad news; in Opera, when you read the scrollTop of the body it is correctly 0, since the body is not scrollable within the document. But Opera will scroll the viewport if you set the scrolling offset on either the "html" or "body" . As a result, the animation sets two properties, once for the "html" and once for the "body". The first starts at the right place, while the second starts at 0, causing the flicker and odd scroll position.

Better solution not involving user agent sniffing

From http://w3fools.com/js/script.js

    // find out what the hell to scroll ( html or body )
    // its like we can already tell - spooky
    if ( $docEl.scrollTop() ) {
        $scrollable = $docEl;
    } else {
        var bodyST = $body.scrollTop();
        // if scrolling the body doesn't do anything
        if ( $body.scrollTop( bodyST + 1 ).scrollTop() == bodyST) {
            $scrollable = $docEl;
        } else {
            // we actually scrolled, so, er, undo it
            $body.scrollTop( bodyST - 1 );
        }
    }

这个http://www.zachstronaut.com/posts/2009/01/18/jquery-smooth-scroll-bugs.html#opera可能是一个更好的解决方案,不使用任何Opera特定的功能和计算怪癖模式。

Yep! I had a problem with action of animate({scrollTop: }) function called in click() function.

The best way is http://www.zachstronaut.com/posts/2009/01/18/jquery-smooth-scroll-bugs.html#opera , which was written here by Divya Manian .

One need to use event.preventDefault() before calling scroll function or animate function to end click event before start scroll event.

Something like this:

$(<clicked_element>).click(function(event){
    event.preventDefault();
    $('html, body').animate({scrollTop: <value>}, 600);
});

EDIT: It's important to apply scroll method to $('html, body') elements

$("body:not(:animated)").animate({ scrollTop: destination}, 500 );
return false;

works for me, in opera as well.

EDIT: does not work in firefox though

I've had this problem, too. This is what I use and it works. It's not browser sniffing, but it's not particularly nice code, to me. It works tho, for now.

Calling scrollTop on html element in Opera 11 / IE 8 / FF 3.6 returns a number larger than zero

Calling scrollTop on html element in Chrome 10 / Flock 3.5 / Safari 5 (for Windows) returns 0

So just test that:

If the browser is Opera, you test for a number larger than 0 on scrollTop, and call scrollTop on only html, a la

var html = document.getElementsByTagName('html')[0]; var body = document.getElementsByTagName('body')[0]; $(html).animate({scrollTop:0+'px'},{'duration':1000,'easing':'swing'});

var html = document.getElementsByTagName('html')[0]; var body = document.getElementsByTagName('body')[0]; $(html).animate({scrollTop:0+'px'},{'duration':1000,'easing':'swing'});

var html = document.getElementsByTagName('html')[0]; var body = document.getElementsByTagName('body')[0]; $(html).animate({scrollTop:0+'px'},{'duration':1000,'easing':'swing'});

If the browser is Chrome, or Flock or Safari than scrollTop will return 0 and you test for that, acting accordingly:

$(html,body).animate({scrollTop:0+'px'},{'duration':1000,'easing':'swing'});

So, you'll set the effect on html for standards mode FF and IE (quirks should be covered, too. Ugh), and body for Chrome and Safari.

In Opera, which attempts to scroll both html and body, thus leading to mass freakishness, scrollTop returns a number greater than 0, so you call only html and you don't get the flickery nonsense.

So you can safely use both html and body when necessary, or just html when the browser is Opera.

And don't forget yer preventDefault() or that'll be another weird flicker you'll have to worry about. ;)

Hey, I'm no JS ninja, but I try hard and this works for me, and I don't have time right now to investigate it as much as I'd like, so I thought I'd post this here and help. If I'm wrong I'll hold up my hands and say it. ;) So feedback, please. :D

Tom.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM