파이어 폭스에서 작동하지 않는 Animate scrollTop


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

2
최종 코드는 여기에서 가장 우아합니다.
Lizardx

답변:


331

Firefox는 html특별히 다르게 동작하도록 스타일이 지정되지 않은 한 오버플로를 수준에 둡니다.

Firefox에서 작동하게하려면

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

작업 예

CSS 솔루션은 다음 스타일을 설정하는 것입니다.

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

JS 솔루션이 가장 덜 침습적이라고 가정합니다.


최신 정보

아래의 많은 논의 scrollTop는 두 요소 를 애니메이션 하면 콜백이 두 번 호출 된다는 사실에 중점을 둡니다 . 브라우저 감지 기능이 제안되어 이후에는 더 이상 사용되지 않으며, 일부는 상당히 멀리 가져 왔습니다.

콜백이 dem 등원이고 많은 컴퓨팅 성능이 필요하지 않은 경우 콜백이 두 번 발생하면 문제가되지 않을 수 있습니다. 콜백의 여러 호출이 실제로 문제가되고 기능 감지를 피하려면 콜백 내에서 콜백이 한 번만 실행되도록하는 것이 더 간단 할 수 있습니다.

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');
}));

51
JS 솔루션에 결함이 있습니다! html 요소와 body 요소 각각에 대해 애니메이션 함수가 두 번 실행 됩니다. Webkit 브라우저는 body를 사용 하고 나머지는 html을 사용하는 것처럼 보입니다 . 이 수정은 작업을 수행해야합니다$(jQuery.browser.webkit ? "body": "html").animate(...);
Andreyco

2
Andreyco의 솔루션이 사용중인 jQuery <1.4에서 작동하지 않는 것으로 나타났습니다. 나는 이것을 다음과 같이 고칠 수 있었다 : $(jQuery.browser.mozilla ? "html" : "body").animate(...);. 찾아보기 스니핑을 사용하지 않고 기능 감지를 사용하는 것이 좋습니다. 그래도 CSS에서 기능 감지를 수행하는 방법을 모르겠습니다
Rustavore

23
참고 jQuery.browser사용되지 않는 최신의 jQuery 버전에서 누락
spiderplant0

2
4 년이 지났지 만이 답변은 여전히 ​​유용합니다. 매우 감사합니다!
Matt

1
@DamFa : 주로 window.scroll움직이지 않기 때문에 . 물론 간격으로 자신의 것을 굴릴 수 있습니다 scrollBy. 여유를 더하고 싶다면 제품의 사소한 부분을 작성하기 위해 갑자기 많은 코드가 필요합니다.
David Hedlund

19

기능 감지 후 지원되는 단일 객체에 애니메이션을 적용하는 것은 좋지만 한 줄 솔루션은 없습니다. 그 동안 실행마다 단일 콜백을 약속하는 방법을 사용합니다.

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

정상적인 상황에서 잘 작동합니다. 감사합니다! 그러나 알아야 할 몇 가지 문제가 있습니다. (1) 기능 테스트가 실행될 때 본문에 창을 오버플로하기에 충분한 내용이 없으면 창은 스크롤되지 않으며 테스트는 가짜 "본문"결과를 반환합니다. (2) 테스트가 iOS의 iframe 내에서 실행되는 경우 동일한 이유로 실패합니다. iOS의 iframe은 내용이 스크롤없이 안에 들어갈 때까지 가로가 아닌 세로로 확장됩니다. (3) 테스트는 기본 창에서 실행되므로 이미 배치되어있는 스크롤 핸들러를 트리거합니다. ... (계속)
hashchange

... 이러한 이유로, 방탄 테스트는 가로 스크롤이 테스트 된 충분한 양의 컨텐츠 (해결 (1))를 가진 전용 iframe (해결 (3)) 내에서 실행해야합니다 (해결 (2)).
hashchange

실제로이 기능을 시간 초과 스크립트에서 실행하여 일관된 결과를 제공해야했습니다. 그렇지 않으면 때로는 반환 html되거나 때로는 반환되는 것처럼 보였습니다 body. 함수를 선언 한 후 내 코드는 다음과 같습니다. var scrollTopElement; setTimeout( function() { scrollTopElement = getScrollTopElement(); console.log(scrollTopElement); }, 1000); 감사합니다. 문제가 해결되었습니다.
Tony M

걱정하지 마십시오. 실제 문제가 무엇인지 알아 냈습니다. 당신이 다시 이미 페이지 하단 (F5)에 있다면,이 스크립트는 반환 html대신 body이되어있는 것처럼. 이것은 웹 페이지를 끝까지 스크롤하고 다시로드하는 경우에만 해당되며 그렇지 않으면 작동합니다.
Tony M

페이지가 맨 아래에 열리는 지 확인한 후 나를 위해 일했습니다.
scott

6

코드가 작동하지 않는 이유를 해결하려고 여러 해를 보냈습니다.

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

문제는 내 CSS에있었습니다.

body { height: 100%};

auto대신에 설정했습니다 ( 100%처음 에 설정 된 이유에 대해 걱정했습니다 ). 그것은 나를 위해 그것을 고쳤다.


2

플러그인을 사용하여 문제를 피하고 싶을 수도 있습니다. 더 구체적으로, 내 플러그인 :)

심각하게, 기본 문제가 해결 된 지 오래되었지만 (다른 브라우저는 창 스크롤에 다른 요소를 사용합니다), 아래로 넘어갈 수있는 사소한 문제가 있습니다.

분명히 편견이 있지만 jQuery.scrollable 은 실제로 이러한 문제를 해결하는 좋은 선택입니다. (사실, 나는 그것들을 모두 처리하는 다른 플러그인을 모른다.)

또한 이 요지 getScrollTargetPosition()기능을 사용하여 대상 위치 (스크롤 한 위치)를 방탄 방식으로 계산할 수 있습니다 .

모두 당신을 떠날 것입니다

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

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

    return false;
}

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 및 탐색기가 작동하지만 Chrome은이를 지원하지 않습니다.

Chrome의 경우 본문, Firefox 및 탐색기의 경우 html이 필요했습니다. jQuery 버그입니까? 몰라

함수는 두 번 실행되므로주의하십시오.


이에 대한 해결 방법을 찾았습니까? 그리고 jquery 브라우저 감지가 더 이상 사용되지 않으므로 크롬과 파이어 폭스를 구별하기 위해 기능 감지를 어떻게 사용할 수 있는지 알 수 없습니다. 그들의 문서는 크롬에 존재하는 기능을 나타내지 않으며 파이어 폭스 또는 그 반대의 기능은 아닙니다. :(
Mandeep Jain 2016

2
.stop (true, true) .animate는 어떻습니까?
Toni Michel Caubet

0

나는 추천 하지 에 의존 body하거나 html더 많은 휴대용 솔루션으로. 스크롤 된 요소를 포함하고 전체 크기 스크롤을 사용하도록 스타일을 지정하는 div를 본문에 추가하십시오.

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

(즉, 가정 display:block;top:0;left:0;목표와 일치하는 기본값입니다), 다음 사용하는 $('#my-scroll')애니메이션에 대해.


0

이것은 실제 거래입니다. Chrome 및 Firefox에서 완벽하게 작동합니다. 어떤 무지한 사람들이 저를 투표한다고 슬프습니다. 이 코드는 문자 그대로 모든 브라우저에서와 같이 완벽하게 작동합니다. 링크를 추가하고 href에 스크롤하려는 요소의 id 만 넣으면 아무것도 지정하지 않고 작동합니다. 순수한 재사용 가능하고 안정적인 코드.

$(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 [];
  }
});

1
복잡 할 수 있지만 실제로 유용합니다. 기본적으로 모든 브라우저에서 Plug-N-Play를 작동합니다. 더 간단한 해결책으로는 그렇게 할 수 없습니다.
drjorgepolanco

0

최근에 같은 문제가 발생했으며 이것을 수행하여 해결했습니다.

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

그리고 youpi! 모든 브라우저에서 작동합니다.

위치가 정확하지 않은 경우이를 수행하여 오프셋 () .top에서 값을 뺄 수 있습니다.

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

이 솔루션은 기존 답변에서 이미 언급되었지만 공유해 주셔서 감사합니다.
Toni Michel Caubet

질문에서 언급 한 바와 같이이 방법은 여전히 파이어 폭스의 결함을 발견, 난 그냥 게시 : stackoverflow.com/q/58617731/1056713
차야 쿠퍼

-3

나에게 문제는 파이어 폭스가 자동으로 URL에 넣은 해시 이름과 같은 이름 속성을 가진 앵커로 뛰어 들었다는 것입니다. 그것을 막기 위해 .preventDefault ()을 넣었더라도. 따라서 이름 속성을 변경 한 후 firefox는 자동으로 앵커로 이동하지 않고 애니메이션을 올바르게 수행했습니다.

@Toni 이해가되지 않으면 죄송합니다. 문제는 www.someurl.com/#hashname과 같은 URL의 해시를 변경 한 것입니다. 그런 다음 예를 들어 <a name="hashname" ...></a>jQuery가 자동으로 스크롤되어야 하는 앵커가 있습니다. 그러나 스크롤 애니메이션이없는 Firefox에서 이름 속성이 일치하는 앵커로 바로 이동했기 때문은 아닙니다. name 속성을 해시 이름과 다른 것으로 변경하면 (예 :로 name="hashname-anchor"스크롤) 작동했습니다.


-5

나를 위해, 애니메이션 시점에서 ID를 추가하는 것을 피하고있었습니다.

피하기 :

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

미리 ID를 준비하고 대신 수행하십시오.

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

FF로 수정되었습니다. (css 추가는 나에게 영향을 미치지 않았습니다)


-8
setTimeout(function(){                               
                   $('html,body').animate({ scrollTop: top }, 400);
                 },0);

이것이 효과가 있기를 바랍니다.


4
여기서 setTimeut이 어떻게 도움이됩니까?
Toni Michel Caubet

2
@ToniMichelCaubet 아마도 목표는 애니메이션을 비동기로 만드는 것입니다. jQuery 애니메이션은 이미 비동기식이므로 아무것도 달성하지 못합니다.
mwcz

문제에 대한 신중한 답변이 아닙니다. 이것이 무엇을 성취 할 지 잘 모르겠습니다.
erier
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.