web-dev-qa-db-fra.com

jQuery scrollTop () ne semble pas fonctionner dans Safari ou Chrome (Windows)

J'ai une configuration simple pour autoriser le chargement et le défilement d'une fenêtre de style "aide" jusqu'à un point particulier de la page. Plus ou moins le code ressemble à ceci:

var target = /* code */;
target.offsetParent().scrollTop(target.offset().top - fudgeValue);

La cible du défilement et la valeur de fudge sont déterminées par quelques indices déposés sur la page, et je n'ai aucun problème avec cette partie de ce mécanisme. Dans Firefox et IE8, le code ci-dessus fonctionne exactement comme je le souhaite: la zone de défilement (dans ce cas, le corps de la page) fait défiler correctement les éléments contenus au bon point dans la fenêtre quand on lui dit de le faire.

Dans Chrome et Safari, cependant, l'appel à scrollTop () ne fait apparemment rien du tout. Tous les chiffres sont OK, et la cible se réfère à la bonne chose (et le offsetParent () est en effet l'élément body), mais rien ne se passe. Pour autant que je puisse en juger par googler, cela est censé fonctionner. Y a-t-il quelque chose de drôle dans le moteur de rendu sous Safari et Chrome?

C'est jQuery 1.3.2 si cela importe.

Page de test: http://gutfullofbeer.net/scrolltop.html

39
Pointy

Oui, il semble y avoir un bogue dans Chrome quand il s'agit de modifier le body, en essayant d'en faire un offsetParent. Comme solution de contournement , Je vous suggère simplement d'ajouter un autre div pour envelopper le #content div, et faire que faire défiler:

html, body { height: 100%; padding: 0; } 
html { width: 100%; background-color: #222; overflow: hidden; margin: 0; } 
body 
{ 
   width: 40em; margin: 0px auto; /* narrow center column layout */
   background-color: white; 
   position: relative; /* allow positioning children relative to this element */
} 
#scrollContainer /* wraps #content, scrolls */
{ 
  overflow: auto; /* scroll! */
  position:absolute; /* make offsetParent */
  top: 0; height: 100%; width: 100%; /* fill parent */
} 
#header 
{ 
  position: absolute; 
  top: 0px; height: 50px; width: 38.5em; 
  background-color: white; 
  z-index: 1; /* sit above #content in final layout */
} 
#content { padding: 5px 14px 50px 5px;  } 

Testé dans FF 3.5.5, Chrome 3.0.195.33, IE8

Démonstration en direct:

$(function() {
        $('#header').find('button').click(function(ev) {
          var button = $(this), target = $('div.' + button.attr('class'));
          var scroll = target.offsetParent().scrollTop(); 
          target.offsetParent().scrollTop(target.offset().top + scroll - 50);
        });
      });
html, body { height: 100%; padding: 0; }
      html { width: 100%; background-color: #222; overflow: hidden; margin: 0; }
      body { width: 40em; margin: 0px auto; background-color: white; position: relative; }
      #scrollContainer { overflow: auto; position:absolute; top: 0; height: 100%; width: 100%; }
      #header { position: absolute; top: 0px; height: 50px; width: 38.5em; background-color: white; z-index: 1; }
      #content { padding: 5px 14px 50px 5px;  }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <div id='header'> 
      Header Box
      <button class='A'>A</button> 
      <button class='B'>B</button> 
      <button class='C'>C</button> 
    </div> 
    <div id='scrollContainer'>
    <div id='content'> 
      <div style='height: 50px'> </div> 
      <div class='A'> 
        <h1>A</h1> 
        <p>My name is Boffer Bings. I was born of honest parents in one of the humbler walks of life, my father being a manufacturer of dog-oil and my mother having a small studio in the shadow of the village church, where she disposed of unwelcome babes. In my boyhood I was trained to habits of industry; I not only assisted my father in procuring dogs for his vats, but was frequently employed by my mother to carry away the debris of her work in the studio. In performance of this duty I sometimes had need of all my natural intelligence for all the law officers of the vicinity were opposed to my mother's business. They were not elected on an opposition ticket, and the matter had never been made a political issue; it just happened so. My father's business of making dog-oil was, naturally, less unpopular, though the owners of missing dogs sometimes regarded him with suspicion, which was reflected, to some extent, upon me. My father had, as silent partners, all the physicians of the town, who seldom wrote a prescription which did not contain what they were pleased to designate as _Ol. can._ It is really the most valuable medicine ever discovered. But most persons are unwilling to make personal sacrifices for the afflicted, and it was evident that many of the fattest dogs in town had been forbidden to play with me--a fact which pained my young sensibilities, and at one time came near driving me to become a pirate.
      </div> 
      <div class='B'> 
        <h1>B</h1> 
        <p> 
        Looking back upon those days, I cannot but regret, at times, that by indirectly bringing my beloved parents to their death I was the author of misfortunes profoundly affecting my future.
        <p> 
        One evening while passing my father's oil factory with the body of a foundling from my mother's studio I saw a constable who seemed to be closely watching my movements. Young as I was, I had learned that a constable's acts, of whatever apparent character, are prompted by the most reprehensible motives, and I avoided him by dodging into the oilery by a side door which happened to stand ajar. I locked it at once and was alone with my dead. My father had retired for the night. The only light in the place came from the furnace, which glowed a deep, rich crimson under one of the vats, casting ruddy reflections on the walls. Within the cauldron the oil still rolled in indolent ebullition, occasionally pushing to the surface a piece of dog. Seating myself to wait for the constable to go away, I held the naked body of the foundling in my lap and tenderly stroked its short, silken hair. Ah, how beautiful it was! Even at that early age I was passionately fond of children, and as I looked upon this cherub I could almost find it in my heart to wish that the small, red wound upon its breast--the work of my dear mother--had not been mortal.
      </div> 
      <div class='C'> 
        <h1>C</h1> 
        <p>It had been my custom to throw the babes into the river which nature had thoughtfully provided for the purpose, but that night I did not dare to leave the oilery for fear of the constable. "After all," I said to myself, "it cannot greatly matter if I put it into this cauldron. My father will never know the bones from those of a puppy, and the few deaths which may result from administering another kind of oil for the incomparable _ol. can._ are not important in a population which increases so rapidly." In short, I took the first step in crime and brought myself untold sorrow by casting the babe into the cauldron.
      </div> 
      <div style='height: 75em;'> </div> 
    </div> 
    </div>
23
Shog9

J'avais ce problème dans Safari et Chrome (Mac) et j'ai découvert que .scrollTop Fonctionnerait sur $("body") mais pas $("html, body"), FF et IE fonctionne cependant dans l'autre sens. Un simple navigateur détecte résout le problème:

if($.browser.safari)
    bodyelem = $("body")
else
    bodyelem = $("html,body")

bodyelem.scrollTop(100)

La valeur du navigateur jQuery pour Chrome est Safari, vous n'avez donc qu'à effectuer une détection à ce sujet.

J'espère que cela aide quelqu'un.

46
Carl
 $("body,html,document").scrollTop($("#map_canvas").position().top);

Cela fonctionne pour Chrome 7, IE6, IE7, IE8, IE9, FF 3.6 et Safari 5.

MISE À JOUR 2012
C'est toujours bon mais j'ai dû le réutiliser. Parfois, position ne fonctionne pas, c'est donc une alternative:

$("body,html,document").scrollTop($("#map_canvas").offset().top);
17
GorillaApe

L'état de prise en charge du navigateur est le suivant:

IE8, Firefox, Opera: $("html")

Chrome, Safari: $("body")

Donc ça marche:

bodyelem = $.browser.safari ? $("body") : $("html") ;
bodyelem.animate( {scrollTop: 0}, 500 );
9
pengkai

Pour le défilement: 'html' ou 'body' pour setter (dépend du navigateur) ... 'window 'pour getter ...

Un jsFiddle pour les tests est ici: http://jsfiddle.net/molokoloco/uCrLa/

var $window = $(window), // Set in cache, intensive use !
    $document = $(document),
    $body = $('body'),
    scrollElement = 'html, body',
    $scrollElement = $();

var isAnimated = false;

// Find scrollElement
// Inspired by http://www.zachstronaut.com/posts/2009/01/18/jquery-smooth-scroll-bugs.html
$(scrollElement).each(function(i) {
    // 'html, body' for setter... window for getter... 
    var initScrollTop = parseInt($(this).scrollTop(), 10);
    $(this).scrollTop(initScrollTop + 1);
    if ($window.scrollTop() == initScrollTop + 1) {
        scrollElement = this.nodeName.toLowerCase(); // html OR body
        return false; // Break
    }
});
$scrollElement = $(scrollElement);

// UTILITIES...
var getHash = function() {
        return window.location.hash || '';
    },
    setHash = function(hash) {
        if (hash && getHash() != hash) window.location.hash = hash;
    },
    getWinWidth = function() {
        return $window.width();
    },
    // iphone ? ((window.innerWidth && window.innerWidth > 0) ? window.innerWidth : $window.width());
    getWinHeight = function() {
        return $window.height();
    },
    // iphone ? ((window.innerHeight && window.innerHeight > 0) ? window.innerHeight : $window.height());
    getPageWidth = function() {
        return $document.width();
    },
    getPageHeight = function() {
        return $document.height();
    },
    getScrollTop = function() {
        return parseInt($scrollElement.scrollTop() || $window.scrollTop(), 10);
    },
    setScrollTop = function(y) {
        $scrollElement.stop(true, false).scrollTop(y);
    },
    myScrollTo = function(y, newAnchror) { // Call page scrolling to a value (like native window.scrollBy(x, y)) // Can be flooded
        isAnimated = true; // kill waypoint AUTO hash
        var duration = 360 + (Math.abs(y - getScrollTop()) * 0.42); // Duration depend on distance...
        if (duration > 2222) duration = 0; // Instant go !! ^^
        $scrollElement.stop(true, false).animate({
            scrollTop: y
        }, {
            duration: duration,
            complete: function() { // Listenner of scroll finish...
                if (newAnchror) setHash(newAnchror); // If new anchor
                isAnimated = false;
            }
        });
    },
    goToScreen = function(dir) { // Scroll viewport page by paginette // 1, -1 or factor
        var winH = parseInt((getWinHeight() * 0.75) * dir); // 75% de la hauteur visible comme unite
        myScrollTo(getScrollTop() + winH);
    };


myScrollTo((getPageHeight() / 2), 'iamAMiddleAnchor');
7
molokoloco

Il y a un bug dans Chrome (pas dans Safari au moment où nous avons vérifié) qui donne des résultats inattendus dans les différentes mesures de largeur et de hauteur de Javascript lors de l'ouverture des onglets en arrière-plan ( détails du bug ici ) - nous avons enregistré le bogue en juin et il n'a pas été résolu depuis.

Il est possible que vous ayez rencontré le bogue dans ce que vous essayez de faire.

2
Ross Duggan

Fonctionne pour Safari, Firefox et IE7 (je n'ai pas essayé IE8). Test simple:

<button onclick='$("body,html").scrollTop(0);'>  Top </button>

<button onclick='$("body,html").scrollTop(100);'> Middle </button>

<button onclick='$("body,html").scrollTop(250);'> Bottom </button>

La plupart des exemples utilisent l'un ou les deux, mais dans l'ordre inverse (c'est-à-dire "html, body").

À votre santé.

(Et les puristes sémantiques là-bas, ne vous arrêtez pas - je le cherche depuis des semaines, c'est un exemple simple, qui valide XHTML strict. N'hésitez pas à créer 27 couches de abstraction et événement contraignant pour votre tranquillité d'esprit de tranquillité d'esprit. Veuillez juste donner le crédit dû, car les gens dans les forums jQuery, SO et le G n'ont pas pu cracher les marchandises. Peace out.)

2
PapaK
setTimeout(function() { 
   $("body,html,document").scrollTop( $('body').height() ); 
}, 100);

Cela devrait probablement fonctionner même si le temps est de 10 ms.

2
Dima

Quel élément est le offsetParent d'un autre n'est pas bien spécifié et peut varier d'un navigateur à l'autre. Il n'est pas garanti d'être le parent déroulant que vous recherchez.

Le corps lui-même ne devrait pas non plus être l'élément principal déroulant de la page. C'est seulement en mode Quirks, que vous voudriez éviter en général.

Les mesures offsetTop/offsetLeft/offsetParent ne sont pas très utiles en elles-mêmes, elles ne sont vraiment fiables que lorsque vous les utilisez en boucle pour obtenir nombre total de coordonnées relatives à la page (comme le fait position() dans jQuery). Vous devez savoir quel est l'élément que vous souhaitez faire défiler et découvrir la différence de coordonnées de page entre celui-ci et le descendant target pour savoir à quel point le faire défiler.

Ou si c'est toujours la page elle-même dont vous parlez, faites simplement défiler location.href= '#'+target.id navigation à la place.

1
bobince

Cela a fonctionné pour moi, laissez-le à jQuery.

$("html,body").animate({ scrollTop: 0 }, 1);

Fondamentalement, vous devez connaître le navigateur et écrire le code en tenant compte des différences de navigateur. Étant donné que jQuery est multi-navigateur, il devrait gérer la première étape. Et enfin vous simulez le moteur js du navigateur en animant le défilement en 1 milliseconde.

1
ozanmuyes

que diriez-vous

var top = $('html').scrollTop() || $('body').scrollTop();
1
Andrew Bullock

Cela semble fonctionner dans FF et WebKit; IE non testé jusqu'à présent.

$(document).scrollTop();
1
Christopher Dell

Je ne sais pas si c'est le cas:

J'utilisais le CDN de Google pour jQuery, c'est-à-dire.

En mettant "https:" avant //ajax.google....... a fonctionné, il semble que Safari l'a reconnu comme un chemin local (vérifié par - Inspecter l'élément)

Désolé, uniquement testé dans Safari 7.0.3 :(

0
pk10

Ce n'est pas vraiment un bug, juste une différence d'implantation par les éditeurs de navigateurs.

En règle générale, évitez de flairer le navigateur. Il existe un correctif jQuery astucieux qui est indiqué dans les réponses.

Voici ce qui fonctionne pour moi: $('html:not(:animated),body:not(:animated)').scrollTop()

0
Egor Kloos

J'étais confronté à ce problème, j'ai créé ce lien en bas et mis en œuvre le code jQuery scrollTop et cela fonctionnait parfaitement dans Firefox, IE, Opera mais ne fonctionnait pas dans Chrome et Safari. J'apprends jQuery donc je ne sais pas si cette solution est techniquement parfaite mais cela a fonctionné pour moi. Je viens d'implémenter 2 codes ScrollTop le premier utilise $ ('html') qui fonctionne pour Firefox , etc. Le second utilise $ ('html body') cela fonctionne pour Chrome et Safari.

$('a#top').click(function() {

    $('html').animate({scrollTop: 0}, 'slow');
    return false;

    $('html body').animate({scrollTop: 0}, 'slow');
    return false;
});
0
Raj

En effet, il semble qu'une animation soit nécessaire pour le faire fonctionner dans Safari. Je me suis retrouvé avec:

if($.browser.safari) 
    bodyelem = $("body");
else 
    bodyelem = $("html,body");

bodyelem.animate({scrollTop:0},{queue:false, duration:100, easing:"linear", complete:callbackFunc});
0
dijipiji

Pour résumer les solutions à partir de quelques questions/réponses:

Si vous voulez obtenir le décalage de défilement actuel utilisez:

$(document).scrollTop()

Pour définir le décalage de défilement utilisez:

$('html,body').scrollTop(x)

Pour animer le défilement, utilisez utilisez:

$('html,body').animate({scrollTop: x});
0
Paul LeBeau

Dans mon cas, le bouton fonctionnait pour deux des 8 liens. Ma solution était

$("body,html,document").animate({scrollTop:$("#myLocation").offset().top},2500);

Cela a également créé un bel effet de défilement

0
Daniel Lefebvre

Il n'y a pas un grand choix d'éléments qui pourraient être attribués automatiquement avec une valeur scrollTop lorsque nous faisons défiler une page Web.

J'ai donc écrit cette petite fonction pour parcourir les éléments probables et retourner celle que nous recherchons.

var grab=function (){
    var el=$();
        $('body#my_body, html, document').each(function(){
            if ($(this).scrollTop()>0) {
                el= ($(this));
                return false;
            }
        })
    return el;
}
//alert(grab().scrollTop());

Dans Google chrome cela nous donnerait le corps, dans IE - HTML.

(Remarque, nous n'avons pas besoin de définir overflow:auto explicitement sur notre html ou corps de cette façon.)

0
Anonymous