ภาพเคลื่อนไหว scrollTop ไม่ทำงานใน firefox


164

ฟังก์ชั่นนี้ใช้งานได้ดี มันเลื่อนร่างกายเพื่อชดเชยภาชนะที่ต้องการ

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

แต่ไม่ใช่ใน Firefox ทำไม?

-EDIT-

เพื่อจัดการกับทริกเกอร์สองครั้งในคำตอบที่ยอมรับได้ฉันขอแนะนำให้หยุดองค์ประกอบก่อนภาพเคลื่อนไหว:

$('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องค์ประกอบสองอย่างนั้นจะทำให้การเรียกกลับถูกเรียกสองครั้ง แนะนำคุณสมบัติการตรวจจับเบราว์เซอร์และเลิกใช้แล้วในภายหลังและบางคุณสมบัติสามารถดึงข้อมูลได้ไกล

หากการเรียกกลับเป็น idempotent และไม่ต้องการพลังการประมวลผลมากการยิงมันสองครั้งอาจไม่ใช่ปัญหาที่สมบูรณ์ หากการเรียกกลับหลายครั้งของการติดต่อกลับเป็นปัญหาอย่างแท้จริงและหากคุณต้องการหลีกเลี่ยงการตรวจจับคุณสมบัติอาจเป็นเรื่องตรงไปตรงมามากขึ้นในการบังคับให้การโทรกลับทำงานเพียงครั้งเดียวจากภายในการโทรกลับ:

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และองค์ประกอบร่างกายตามลำดับ ดูเหมือนว่าเบราว์เซอร์ Webkit ใช้ร่างกายและส่วนที่เหลือจะใช้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
});

ใช้งานได้ดีภายใต้สถานการณ์ปกติขอบคุณ! มีคู่ของ gotchas ที่ต้องระวังอยู่ (1) หากเนื้อหาไม่มีเนื้อหาเพียงพอที่จะล้นหน้าต่างเมื่อการทดสอบคุณสมบัติทำงานหน้าต่างจะไม่เลื่อนและการทดสอบจะส่งกลับผลลัพธ์ "เนื้อหา" ปลอม (2) หากการทดสอบทำงานภายใน iframe ใน iOS มันจะล้มเหลวด้วยเหตุผลเดียวกัน Iframes ใน iOS ขยายในแนวตั้ง (ไม่ใช่แนวนอน) จนกว่าเนื้อหาจะเข้าด้านในโดยไม่ต้องเลื่อน (3) เนื่องจากการทดสอบดำเนินการในหน้าต่างหลักมันจะทริกเกอร์ตัวเลื่อนที่มีอยู่แล้ว ... (ต่อ)
แฮชเชน

... ด้วยเหตุผลเหล่านี้การทดสอบด้วยกระสุนจะต้องทำงานภายใน iframe เฉพาะ (แก้ปัญหา (3)) ที่มีเนื้อหามากพอ (แก้ (1)) ซึ่งได้รับการทดสอบสำหรับเลื่อนแนวนอน (แก้ (2))
hashchange

ที่จริงผมต้องวิ่งฟังก์ชันนี้ในสคริปต์หมดเวลาจะทำให้เรื่องนี้ให้ผลลัพธ์ที่สอดคล้องมิฉะนั้นมันดูเหมือนจะกลับมาบางครั้งและบางครั้งผลตอบแทนhtml bodyนี่คือรหัสของฉันหลังจากประกาศฟังก์ชั่นvar scrollTopElement; setTimeout( function() { scrollTopElement = getScrollTopElement(); console.log(scrollTopElement); }, 1000); ขอบคุณสำหรับสิ่งนี้แม้ว่ามันได้แก้ไขปัญหาของฉันแล้ว
Tony M

ไม่เป็นไรฉันคิดออกว่าปัญหาที่แท้จริงคืออะไร หากคุณอยู่ที่ด้านล่างของหน้าแล้วเมื่อคุณโหลดใหม่ (f5) สคริปต์นี้จะกลับมาhtmlแทนที่จะเป็นbodyอย่างที่ควรจะเป็น นี่คือเฉพาะเมื่อคุณเลื่อนลงมาทางหน้าเว็บและคุณโหลดใหม่มิฉะนั้นมันจะทำงาน
Tony M

สิ่งนี้ใช้ได้กับฉันหลังจากที่ฉันเพิ่มการตรวจสอบหากหน้าเปิดขึ้นที่ด้านล่าง
กอตต์

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

ยอดเยี่ยมมันใช้งานได้ แต่ปัญหาใหม่เนื่องจากมีสององค์ประกอบคือเนื้อหาและ html ฟังก์ชันจะถูกดำเนินการสองครั้งนี่คือ X จะทำงานสองครั้ง

ทดลองใช้กับ 'html' เท่านั้นและ Firefox และ Explorer ทำงานได้ แต่ตอนนี้ Chrome ไม่สนับสนุนสิ่งนี้

ดังนั้นเนื้อหาที่จำเป็นสำหรับ Chrome และ html สำหรับ Firefox และ Explorer มันเป็นข้อผิดพลาด jQuery หรือไม่? ไม่รู้

เพียงระวังฟังก์ชั่นของคุณเพราะมันจะทำงานสองครั้ง


คุณพบวิธีแก้ปัญหาสำหรับสิ่งนี้หรือไม่? และเนื่องจากการตรวจหาเบราว์เซอร์ jquery เลิกใช้แล้วฉันไม่รู้ว่าฉันจะใช้การตรวจจับคุณสมบัติเพื่อแยกความแตกต่างระหว่าง chrome และ firefox ได้อย่างไร เอกสารของพวกเขาไม่ได้ระบุคุณสมบัติที่มีอยู่ในโครเมี่ยมและไม่อยู่ใน firefox หรือ viceversa :(
Mandeep Jain

2
สิ่งที่เกี่ยวกับ. หยุด (จริงจริง). เคลื่อนไหว?
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 และใช้งานได้โดยไม่ต้องระบุอะไรเลย รหัสที่ใช้ซ้ำได้และเชื่อถือได้บริสุทธิ์

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

และคุณล่ะ !!! ใช้ได้กับทุกเบราว์เซอร์

ในกรณีที่ตำแหน่งไม่ถูกต้องคุณสามารถลบค่าจาก offset () .top โดยทำสิ่งนี้

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

วิธีการแก้ปัญหานี้ได้กล่าวถึงแล้วในคำตอบที่มีอยู่ แต่ขอบคุณสำหรับการแบ่งปัน
Toni Michel Caubet

วิธีนี้ยังคงพบข้อผิดพลาดใน Firefox ตามที่ระบุไว้ในคำถามที่ฉันเพิ่งโพสต์: stackoverflow.com/q/58617731/1056713
Chaya Cooper

-3

สำหรับฉันปัญหาคือ firefox กระโดดไปที่จุดยึดโดยอัตโนมัติด้วยชื่อ - แอตทริบิวต์เหมือนกับชื่อแฮชที่ใส่ลงใน URL แม้ว่าฉันจะใส่ .preventDefault () เพื่อป้องกันสิ่งนั้น ดังนั้นหลังจากเปลี่ยนแอตทริบิวต์ชื่อแล้ว firefox จะไม่ข้ามไปที่จุดยึดโดยอัตโนมัติ

@Toni ขออภัยหากนี่ไม่เข้าใจ สิ่งที่ฉันเปลี่ยนแฮชใน URL เช่น www.someurl.com/#hashname จากนั้นฉันมีตัวอย่างเช่นสมอ<a name="hashname" ...></a>ที่ jQuery ควรเลื่อนไปโดยอัตโนมัติ แต่มันไม่ได้เป็นเพราะมันกระโดดไปทางด้านขวาด้วยแอททริบิวต์ชื่อที่ตรงกันใน Firefox โดยไม่มีภาพเคลื่อนไหวการเลื่อน เมื่อฉันเปลี่ยนแอตทริบิวต์ชื่อเป็นสิ่งที่แตกต่างจากชื่อแฮเช่นname="hashname-anchor"การเลื่อนทำงาน


-5

สำหรับฉันมันคือการหลีกเลี่ยงการต่อท้าย ID ที่จุดของการเคลื่อนไหว:

หลีกเลี่ยง:

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

เตรียมรหัสไว้ล่วงหน้าและทำสิ่งนี้แทน:

 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.