164

此功能工作正常。它将正文滚动到所需容器的偏移量

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);
4

11 回答 11

331

Firefox 将溢出放置在html级别,除非特别设置为不同的行为。

要让它在 Firefox 中工作,请使用

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

工作示例

CSS 解决方案是设置以下样式:

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

我会假设 JS 解决方案的侵入性最小。


更新

scrollTop下面的很多讨论都集中在动画两个元素会导致回调被调用两次的事实。浏览器检测功能已被提出并随后被弃用,有些可以说是相当牵强的。

如果回调是幂等的并且不需要大量的计算能力,那么触发它两次可能完全不是问题。如果回调的多次调用确实是一个问题,并且如果您想避免功能检测,则强制回调仅在回调中运行一次可能更直接:

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');
}));
于 2011-11-16T09:18:03.643 回答
19

特征检测然后在单个受支持的对象上制作动画会很好,但没有单一的解决方案。同时,这里有一种使用 Promise 每次执行执行单个回调的方法。

$('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();

现在使用我们刚刚定义的 var 作为页面滚动动画的选择器,并使用常规语法:

$(scrollTopElement).animate({ scrollTop: 100 }, 500, function() {
    // normal callback
});
于 2014-02-05T17:04:25.193 回答
6

我花了很长时间试图弄清楚为什么我的代码不起作用 -

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

问题出在我的CSS中-

body { height: 100%};

我将其设置为auto(并且担心为什么100%首先将其设置为)。那为我修好了。

于 2014-03-02T19:53:08.623 回答
2

您可能想通过使用插件来躲避这个问题——更具体地说,我的插件:)

说真的,尽管基本问题早已得到解决(不同的浏览器使用不同的元素来滚动窗口),但仍有不少不平凡的问题可能会让您大吃一惊:

我显然有偏见,但jQuery.scrollable实际上是解决这些问题的好选择。(事实上​​,我不知道有任何其他插件可以处理它们。)

此外,您可以使用此要点中getScrollTargetPosition()功能以防弹的方式计算目标位置(您滚动到的位置)。

所有这些都会让你留下

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

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

    return false;
}
于 2015-11-05T23:37:32.910 回答
1

谨防这一点。我遇到了同样的问题,Firefox 或 Explorer 都没有滚动

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

所以我像大卫说的那样使用

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

很好用,但是新问题,因为有两个元素,body 和 html,函数被执行了两次,也就是说,X 运行了两次。

仅尝试使用“html”,Firefox 和 Explorer 也可以工作,但现在 Chrome 不支持此功能。

因此,Chrome 需要 body,Firefox 和 Explorer 需要 html。它是一个 jQuery 错误吗?不知道。

请注意您的功能,因为它会运行两次。

于 2013-05-28T02:24:13.443 回答
0

我建议不要依赖body也不html作为更便携的解决方案。只需在 body 中添加一个 div,该 div 旨在包含滚动元素并设置其样式以启用全尺寸滚动:

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

(假设display:block;top:0;left:0;是与您的目标相匹配的默认值),然后$('#my-scroll')用于您的动画。

于 2015-02-18T15:50:00.963 回答
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 [];
  }
});
于 2015-03-07T04:37:37.333 回答
0

我最近遇到了同样的问题,我通过这样做解决了它:

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

还有你皮!!!它适用于所有浏览器。

如果定位不正确,您可以通过执行此操作从 offset () .top 中减去一个值

$ ('html, body'). animate ({scrollTop: $ ('. class_of_div'). offset () .top-desired_value}, 'fast'});
于 2018-10-16T14:58:34.450 回答
-3

对我来说,问题是 Firefox 自动跳转到名称属性与我放入 URL 中的哈希名称相同的锚点。即使我放了 .preventDefault() 来防止这种情况。所以更改name属性后,firefox并没有自动跳转到锚点,而是正确执行动画。

@Toni 抱歉,如果这无法理解。问题是我更改了 URL 中的哈希值,例如 www.someurl.com/#hashname。然后我有一个锚点,比如<a name="hashname" ...></a>jQuery 应该自动滚动到的锚点。但它没有,因为它在没有任何滚动动画的情况下直接跳转到 Firefox 中具有匹配名称属性的锚点。一旦我将 name 属性更改为与哈希名称不同的名称,例如更改为name="hashname-anchor",滚动就起作用了。

于 2013-05-20T13:33:55.100 回答
-5

对我来说,这是避免在动画点附加 ID:

避免:

 scrollTop: $('#' + id).offset().top

事先准备好 id 并改为这样做:

 scrollTop: $(id).offset().top

固定在FF中。(CSS添加对我没有影响)

于 2013-05-15T06:56:05.097 回答
-8
setTimeout(function(){                               
                   $('html,body').animate({ scrollTop: top }, 400);
                 },0);

希望这有效。

于 2013-05-14T13:21:00.330 回答