web-dev-qa-db-ja.com

FirefoxでscrollTopが機能しない

この機能は正常に動作します。目的のコンテナのオフセットまで本体をスクロールします

function scrolear(destino){
    var stop = $(destino).offset().top;
    var delay = 1000;
    $('body').animate({scrollTop: stop}, delay);
    return false;
}

しかし、Firefoxではそうではありません。どうして?

-編集-

受け入れられた答えでデダブルトリガーを処理するには、アニメーションの前に要素を停止することをお勧めします。

$('body,html').stop(true,true).animate({scrollTop: stop}, delay);
163

Firefoxは、異なる動作をするよう特別にスタイル設定されていない限り、htmlレベルでオーバーフローを配置します。

Firefoxで動作させるには、以下を使用します

$('body,html').animate( ... );

実施例

CSSソリューションは、次のスタイルを設定することです。

html { overflow: hidden; height: 100%; }
body { overflow: auto; height: 100%; }

JSソリューションは最も侵襲性が低いと思います。


更新

以下の説明の多くは、2つの要素のscrollTopをアニメートすると、コールバックが2回呼び出されるという事実に焦点を当てています。ブラウザー検出機能が提案され、その後廃止されました。一部の機能は、おそらくかなり手に負えないものです。

コールバックがべき等であり、多くの計算能力を必要としない場合、2回呼び出すことは完全に問題ではないかもしれません。コールバックの複数の呼び出しが本当に問題であり、機能の検出を回避したい場合、コールバックがコールバック内から1回だけ実行されるように強制する方が簡単です。

function runOnce(fn) { 
    var count = 0; 
    return function() { 
        if(++count == 1)
            fn.apply(this, arguments);
    };
};

$('body, html').animate({ scrollTop: stop }, delay, runOnce(function() {
   console.log('scroll complete');
}));
330
David Hedlund

機能を検出し、サポートされている単一のオブジェクトをアニメーション化するのはいいことですが、1行のソリューションはありません。それまでの間、promiseを使用して実行ごとに1つのコールバックを実行する方法を次に示します。

$('html, body')
    .animate({ scrollTop: 100 })
    .promise()
    .then(function(){
        // callback code here
    })
});

更新:機能検出を代わりに使用する方法を次に示します。このコードの塊は、アニメーションを呼び出す前に評価する必要があります。

// Note that the DOM needs to be loaded first, 
// or else document.body will be undefined
function getScrollTopElement() {

    // if missing doctype (quirks mode) then will always use 'body'
    if ( document.compatMode !== 'CSS1Compat' ) return 'body';

    // if there's a doctype (and your page should)
    // most browsers will support the scrollTop property on EITHER html OR body
    // we'll have to do a quick test to detect which one...

    var html = document.documentElement;
    var body = document.body;

    // get our starting position. 
    // pageYOffset works for all browsers except IE8 and below
    var startingY = window.pageYOffset || body.scrollTop || html.scrollTop;

    // scroll the window down by 1px (scrollTo works in all browsers)
    var newY = startingY + 1;
    window.scrollTo(0, newY);

    // And check which property changed
    // FF and IE use only html. Safari uses only body.
    // Chrome has values for both, but says 
    // body.scrollTop is deprecated when in Strict mode.,
    // so let's check for html first.
    var element = ( html.scrollTop === newY ) ? 'html' : 'body';

    // now reset back to the starting position
    window.scrollTo(0, startingY);

    return element;
}

// store the element selector name in a global var -
// we'll use this as the selector for our page scrolling animation.
scrollTopElement = getScrollTopElement();

ここで、ページスクロールアニメーションのセレクターとして定義した変数を使用し、通常の構文を使用します。

$(scrollTopElement).animate({ scrollTop: 100 }, 500, function() {
    // normal callback
});
19
Stephen

私のコードが機能しない理由を解明しようと長い間費やしました-

$('body,html').animate({scrollTop: 50}, 500);

問題は私のCSSにありました-

body { height: 100%};

代わりにautoに設定しました(最初に100%に設定された理由について心配していました)。それは私のためにそれを修正しました。

6
Aidan Ewen

プラグインを使用して問題を回避したい場合があります。具体的には、 my plugin :)

真剣に、基本的な問題は長い間対処されてきましたが(異なるブラウザはウィンドウのスクロールに異なる要素を使用します)、後を追う可能性のある重要な問題がかなりあります:

私は明らかに偏っていますが、 jQuery.scrollable は実際にこれらの問題に対処するための良い選択です。 (実際、それらをすべて処理する他のプラグインは知りません。)

さらに、 このGistのgetScrollTargetPosition()関数 を使用して、防弾方式でターゲット位置(スクロールする位置)を計算できます。

すべてがあなたを残すだろう

function scrolear ( destino ) {
    var $window = $( window ),
        targetPosition = getScrollTargetPosition ( $( destino ), $window );

    $window.scrollTo( targetPosition, { duration: 1000 } );

    return false;
}
2
hashchange

これに注意してください。 FirefoxとExplorerのどちらでもスクロールできないという同じ問題がありました

$('body').animate({scrollTop:pos_},1500,function(){do X});

だからデビッドが言ったように使った

$('body, html').animate({scrollTop:pos_},1500,function(){do X});

うまくいきましたが、新しい問題です。bodyとhtmlの2つの要素があるため、関数が2回実行されます。つまり、Xは2回実行されます。

'html'のみで試行し、FirefoxとExplorerは動作しますが、現在Chromeはこれをサポートしていません。

そのため、Chromeにはbody、FirefoxとExplorerにはhtmlが必要でした。 jQueryのバグですか?わからない。

関数は2回実行されるため、注意してください。

1
Avenida Gez

notよりポータブルなソリューションとしてbodyまたはhtmlに依存することをお勧めします。スクロール要素を含むことを目的としたdivを本体に追加し、フルサイズのスクロールを有効にするようにスタイルを設定します。

#my-scroll {
  position: absolute;
  width: 100%;
  height: 100%;
  overflow: auto;
}

display:block;top:0;left:0;が目標に一致するデフォルトであると仮定して)、アニメーションに$('#my-scroll')を使用します。

0
Javarome

私は最近同じ問題に遭遇し、これを行うことでそれを解決しました:

$ ('html, body'). animate ({scrollTop: $ ('. class_of_div'). offset () .top}, 'fast'});

そしてyoupi !!!すべてのブラウザで動作します。

位置が正しくない場合は、これを行うことでオフセット().topから値を引くことができます

$ ('html, body'). animate ({scrollTop: $ ('. class_of_div'). offset () .top-desired_value}, 'fast'});
0

これが本当の取引です。 ChromeおよびFirefoxで問題なく動作します。いくつかの無知な人が私に投票しないのは悲しいことです。このコードは、すべてのブラウザーで文字通り完全に機能します。リンクを追加し、スクロールする要素のIDをhrefに入れるだけで、何も指定しなくても機能します。再利用可能で信頼できる純粋なコード。

$(document).ready(function() {
  function filterPath(string) {
    return string
    .replace(/^\//,'')
    .replace(/(index|default).[a-zA-Z]{3,4}$/,'')
    .replace(/\/$/,'');
  }
  var locationPath = filterPath(location.pathname);
  var scrollElem = scrollableElement('html', 'body');

  $('a[href*=#]').each(function() {
    var thisPath = filterPath(this.pathname) || locationPath;
    if (locationPath == thisPath
    && (location.hostname == this.hostname || !this.hostname)
    && this.hash.replace(/#/,'') ) {
      var $target = $(this.hash), target = this.hash;
      if (target) {
        var targetOffset = $target.offset().top;
        $(this).click(function(event) {
          event.preventDefault();
          $(scrollElem).animate({scrollTop: targetOffset}, 400, function() {
            location.hash = target;
          });
        });
      }
    }
  });

  // use the first element that is "scrollable"
  function scrollableElement(els) {
    for (var i = 0, argLength = arguments.length; i <argLength; i++) {
      var el = arguments[i],
          $scrollElement = $(el);
      if ($scrollElement.scrollTop()> 0) {
        return el;
      } else {
        $scrollElement.scrollTop(1);
        var isScrollable = $scrollElement.scrollTop()> 0;
        $scrollElement.scrollTop(0);
        if (isScrollable) {
          return el;
        }
      }
    }
    return [];
  }
});
0
drjorgepolanco