Henry: scrollTop onscroll Unterschiede im Browser

Hallo,

Ich suche die bestmögliche Vorgehensweise(nicht die Eventüberwachung, nur die Ausführungen) beim Auslesen der Scrollaktivitäten. Leider gibt es ja viele Möglichkeiten und einige mit überraschenden Ergebnissen.

Beispiel , onscroll im BODY-Tag, funktioniert im FF, nicht aber im IE, warum?

Es funktioniert kurioserweise im IE, wenn ich das onscroll Event im HTML-Tag platziere, was natürlich nicht erlaubt ist und dann auch richtigerweise vom FF ignoriert wird.

Es funktioniert mit beiden, wenn ich den Aufruf mit windows.onscroll, document.onscroll oder document.documentElement.onscroll (welche davon ist eigentlich sinnvoller?) aufrufe und eine zusätzliche Funktion erzeuge:

<!DOCTYPE html>
<html>
<head>
<script>
function scrollcntrl() 
{
document.getElementsByTagName('h2')[0].innerHTML = document.documentElement.scrollTop;
}

window.onscroll = function(){scrollcntrl()};

// warum reicht hier eigentlich nicht: window.onscroll = scrollcntrl();


</script>
</head>
<body style="height:1500px">

<div style="position:fixed;">
<h1>Scroll mal...</h1>
<h2>x</h2>
</div>

</body>
</html>

Und, warum reagieren beider Browser nur auf document.documentElement.scrollTop aber nicht auf document.body.scrollTop?

Gruss
Henry

  1. hallo

    Ohne jetzt auf die Unterschiede einzugehen, warum benutzt du nicht reale Sprungziele? Schliesslich möchtest du ja einen bestimmten Inhalt wieder in den Fokus bekommen?

    An Stelle von el.on{event} wäre zudem die DOM Methode el.addEventListener(event, handler) ratsam.

    Weiter weiss ich nicht, was du überhaupt mit el.onscroll( scroll ) erreichen willst. Klingt irgendwie nicht sinnvoll.

    1. Hallo beatovich,

      Ohne jetzt auf die Unterschiede einzugehen, warum benutzt du nicht reale Sprungziele? Schliesslich möchtest du ja einen bestimmten Inhalt wieder in den Fokus bekommen?

      Nein

      An Stelle von el.on{event} wäre zudem die DOM Methode el.addEventListener(event, handler) ratsam.

      Klar, aber wie ich schon sagte, mir geht's hier nicht um die Eventüberwachung als solche.

      Weiter weiss ich nicht, was du überhaupt mit el.onscroll( scroll ) erreichen willst. Klingt irgendwie nicht sinnvoll.

      och, da gibt's viele Möglichkeiten, für mich im Moment experimentelle Neugier.

      Gruss
      Henry

      1. hallo

        Hallo beatovich,

        Ohne jetzt auf die Unterschiede einzugehen, warum benutzt du nicht reale Sprungziele? Schliesslich möchtest du ja einen bestimmten Inhalt wieder in den Fokus bekommen? Nein

        An Stelle von el.on{event} wäre zudem die DOM Methode el.addEventListener(event, handler) ratsam.

        Klar, aber wie ich schon sagte, mir geht's hier nicht um die Eventüberwachung als solche.

        Weiter weiss ich nicht, was du überhaupt mit el.onscroll( scroll ) erreichen willst. Klingt irgendwie nicht sinnvoll.

        och, da gibt's viele Möglichkeiten, für mich im Moment experimentelle Neugier.

        Ich kann auf der verlinkten Seite aber nichts entdecken, das deinem Beispiel nur annähernd entspricht.

        Was machen denn die Browser bei:

        el.onscroll=function(){console.log("handler wird ausgeführt")};

        ???

        1. Hallo beatovich,

          Ich kann auf der verlinkten Seite aber nichts entdecken, das deinem Beispiel nur annähernd entspricht.

          Mein Beispiel ist eine Frage, keine spezifische Anwendung. Aber klar dürfte damit sein, dass ich keine Sprungziele im Auge habe, sondern Ereignisse/Aktionen die sich nach dem Scrollverhalten richten, was dann wohl doch durchaus sinnvoll sein kann.

          Was machen denn die Browser bei:

          el.onscroll=function(){console.log("handler wird ausgeführt")};

          Sie reagieren natürlich darauf, entspricht ja auch meinem Beispielcode(im Thread) hier und der funktioniert, wie schon gesagt, in beiden Browsern.

          Gruss
          Henry

          1. hallo

            Hallo beatovich,

            Ich kann auf der verlinkten Seite aber nichts entdecken, das deinem Beispiel nur annähernd entspricht.

            Mein Beispiel ist eine Frage, keine spezifische Anwendung. Aber klar dürfte damit sein, dass ich keine Sprungziele im Auge habe, sondern Ereignisse/Aktionen die sich nach dem Scrollverhalten richten, was dann wohl doch durchaus sinnvoll sein kann.

            Was machen denn die Browser bei:

            el.onscroll=function(){console.log("handler wird ausgeführt")};

            Sie reagieren natürlich darauf, entspricht ja auch meinem Beispielcode(im Thread) hier und der funktioniert, wie schon gesagt, in beiden Browsern.

            Gruss
            Henry

            Ich kann nur sagen, dass document.body.scrollTop in IE bis in neuere Versionen nicht existiert und du wirst wohl eine property Abfrage machen müssen oder eben deine hier verwendete Variante verwenden müssen. Oder um's anders zu sagen, Browser verhalten sich wohl verschieden in der Frage ob sie den overflow auf der body oder dem html (documentElement) anwenden.

            Eine andere Frage:

            // warum reicht hier eigentlich nicht: window.onscroll = scrollcntrl();

            scrollcntl() würde sofort evaluiert und ganz einfach der zur Zeit der Evaluation ermittelte Wert gespeichert.

            Deshalb besser:

            window.addEventListener("scroll", scrollcntrl);

            Bei

            window.onscroll=function(){scrollcntrl()};

            wird eine anonyme Funktion zugewiesen, und im Eventfall erst ausgeführt. Nachteil natürlich dass derart ein bestehender scrollevent überschrieben wird.

            1. hallo

              Ich kann nur sagen, dass document.body.scrollTop in IE bis in neuere Versionen nicht existiert und du wirst wohl eine property Abfrage machen müssen oder eben deine hier verwendete Variante verwenden müssen. Oder um's anders zu sagen, Browser verhalten sich wohl verschieden in der Frage ob sie den overflow auf der body oder dem html (documentElement) anwenden.

              Theorie: Damit document.body.scrollTop anwendbar ist, muss das body-Element das html-Element überfliessen.

  2. @@Henry

    function scrollcntrl() 
    {
    document.getElementsByTagName('h2')[0].innerHTML = document.documentElement.scrollTop;
    }
    
    window.onscroll = function(){scrollcntrl()};
    
    // warum reicht hier eigentlich nicht: window.onscroll = scrollcntrl();
    

    Weil das, was du window.onscroll zuweist, eine Funktionsreferenz sein muss. [MDN]

    function () { scrollcntrl(); } ist eine anonyme Funktion, die wiederum scrollcntrl aufruft.

    scrollcntrl() ist keine Funktionsreferenz, sondern ein Funktionsaufruf; er liefert den Rückgabewert der Funktion scrollcntrl. (Da in dieser Funktion kein return vorkommt, dürfte der Rückgabewert null sein.)

    Funktionsreferenz zuweisen ginge so: window.onscroll = scrollcntrl;


    Dass man .on… grundsätzlich nicht verwenden sollte, hat beatovich ja schon gesagt. Was in MDN steht (Element.onscroll is equivalent to element.addEventListener("scroll" ... )) stimmt nämlich nicht:

    window.onscroll = foo;
    window.onscroll = bar;
    

    Die zweite Angabe überschreibt die erste. Beim Feuern des Events wird nur bar() ausgeführt.

    window.addEventListener('scroll', foo);
    window.addEventListener('scroll', bar);
    

    Es werden zwei EventListener definiert. Beim Feuern des Events werden foo() und bar() ausgeführt.


    Generell sollte man die Überwachung des scroll-Events besser vermeiden. Stromfresser, performance killer.

    LLAP 🖖

    --
    „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
    1. Hallo Gunnar,

      Dass man .on… grundsätzlich nicht verwenden sollte, hat beatovich ja schon gesagt.

      warum? .on… und addEventListener sind zwei unterschiedliche Wege, Eventhandler zu notieren, mit unterschiedlichen Ergebnissen. Und je nach gewünschtem Ergebnis nehme ich den einen oder den anderen Weg.

      Ein pauschales „.on… grundsätzlich nicht verwenden sollte“ ist mMn falsch.

      Gruß
      Jürgen

    2. @@Gunnar Bittersmann

      (Da in dieser Funktion kein return vorkommt, dürfte der Rückgabewert null sein.)

      Wohl eher undefined.

      LLAP 🖖

      --
      „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
    3. Hallo Gunnar,

      erst mal danke an alle für die bisherigen Antworten. Selten, dass ich nicht weiß, was hier als beste Antwort zählen könnte, weil jede für sich einen Teil des Rätsels löst. Perfekte Zusammenarbeit. Es bleiben nur wenige Puzzlestücke unklar.

      IE kennt document.body.scrolltop nicht, FF schon. Dennoch könnte ich das Beispiel nicht ändern in document.getElementsByTagName('h2')[0].innerHTML = document.body.scrollTop; obwohl ich durchaus <script>document.body.onscroll = function(){scrollcntrl()};</script> als Aufruf benutzen kann.

      Oder mal eine Variante des Beispiels von w3schools. Dort erfolgt der Aufruf durch document.body.scrollTop || document.documentElement.scrollTop , dennoch reagiert FF nicht auf ersteres, was sich zeigt wenn man es entfernt oder eben nur das drin lässt.

      Btw. selfhtml empfiehlt scrollY dem scrollTop, vorzuziehen, warum eigentlich?

      Generell sollte man die Überwachung des scroll-Events besser vermeiden. Stromfresser, performance killer.

      Gut zu wissen. Aber wüsstest du Alternativen um auf Scrollaktionen zu reagieren. Zumindest für die beliebtesten Fälle, also Inhalte nachladen oder Designänderungen ab scrollpunkt xy?

      Falls keine Alternative und es so an die Performance geht, wäre es dann vielleicht sinnvoll die Überwachung erst bei Aktion(mouse, touch, focus, etc...) zu aktivieren und bei keiner Aktion zu deaktivieren? Bzw. Oder ist das scrollevent schon von Haus aus so ausgelegt?

      Gruss
      Henry

  3. Hallo Henry,

    bei der Abfrage der Scrollposition muss man die Browserunterschiede berücksichtigen. Ich mache das so:

    		if(window.scrollY) pos = window.scrollY;
    		else if(document.documentElement.scrollTop) pos = document.documentElement.scrollTop; // IE
    		else pos = 0;
    

    Gruß
    Jürgen

    1. @@JürgenB

      Ich mache das so:

      		if(window.scrollY) pos = window.scrollY;
      		else if(document.documentElement.scrollTop) pos = document.documentElement.scrollTop; // IE
      		else pos = 0;
      

      Was du kürzer (was in dem Fall wohl auch besser lesbar heißt) schreiben kannst:

      pos = window.scrollY || document.documentElement.scrollTop || 0;
      

      pos wurde voher schon definiert? Ansonsnsten sollte da var pos = stehen; wir wollen ja keine globalen Variablen.

      LLAP 🖖

      --
      „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
      1. Hallo Gunnar,

        Was du kürzer (was in dem Fall wohl auch besser lesbar heißt) schreiben kannst:

        pos = window.scrollY || document.documentElement.scrollTop || 0;
        

        wobei das || 0 wohl immer false liefert und pos in diesem Fall undefined ist. Aber ich habe beim Testen keinen Browser mehr gehabt, der nicht entweder scrollY oder scrollTop kannte.

        pos wurde voher schon definiert? Ansonsnsten sollte da var pos = stehen; wir wollen ja keine globalen Variablen.

        seit alle meine Scripe mit "use strict" beginnen, vergesse ich kein var mehr.

        Gruß
        Jürgen

        1. @@JürgenB

          Was du kürzer (was in dem Fall wohl auch besser lesbar heißt) schreiben kannst:

          pos = window.scrollY || document.documentElement.scrollTop || 0;
          

          wobei das || 0 wohl immer false liefert und pos in diesem Fall undefined ist.

          Nei-en! a || b |||| z liefert i.A. keinen booleschen Wert, sondern den ersten Wert, der truthy ist, und wenn es keinen solchen gibt, dann den letzten Wert.

          (Wenn a bis z allesamt boolesche Werte sind, dann kommt natürlich auch ein boolescher Wert heraus.)

          null || 1 || 0      // ergibt 1
          
          null || null || 0   // ergibt 0
          

          LLAP 🖖

          --
          „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
          1. Hallo Gunnar,

            Danke, war mir bisher so nicht bewusst, wieder was dazu gelernt.

            Gruß
            Jürgen

        2. Hallo JürgenB,

          seit alle meine Scripe mit "use strict" beginnen, vergesse ich kein var mehr.

          Guter Hinweis, hatte ich schon gar nicht mehr auf dem Schirm, und für andere Leser nochmal als Link.

          Fand ich übrigens schon immer merkwürdig, dass Variablen innerhalb JS-Funktionen von Haus aus global sind, erst durch Zusatz von var nicht mehr, umgekehrt wäre irgendwie logischer.

          Gruss
          Henry

          1. Tach!

            Fand ich übrigens schon immer merkwürdig, dass Variablen innerhalb JS-Funktionen von Haus aus global sind, erst durch Zusatz von var nicht mehr, umgekehrt wäre irgendwie logischer.

            Das wäre zwar für einen PHP-Programmierer logisch, dafür ist es in anderen Sprachen üblich, dass globale Dinge lokal sichtbar sind, solange keine Deklaration einer lokalen Variable die globale überdeckt. Man fällt nur bei Javascript etwas auf die Nase, weil da Variablen nicht deklariert werden müssen vor dem ersten Gebrauch. Wenn man aber von einer Sprache mit Deklarationszwang kommt, fühlt es sich wohl eher natürlicher an, das var zu schreiben.

            dedlfix.