Henry: JS kann Styleangeben nicht lesen?

Hallo,

ich wollte mit Javascript den aktuellen Displayzustand eines Elements auslesen. Seltsamerweise und überraschend funktioniert das aber offensichtlich nur wenn die Styleangabe direkt im Element eingebaut ist. Warum?

*Das folgende Beispiel habe ich erfolglos versucht bei Fiddle und Dabblet einzutragen. Wäre dankbar für Alternativmöglichkeiten(außer CodePen).

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>JS read CSS</title>

<style>
#p1{display:block;}
</style>

<script type="text/javascript">
function showcss(id)
{
var navobj = document.getElementById(id).style.display;
alert(navobj);
}
</script>

</head>
<body>

<p id="p1">#p1 Hier im Style deklariert</p>
<p id="p2" style="display:block;">#p2 Hier im Element deklariert</p>
<p>
<button onclick="showcss('p1');">Eigenschaft von #p1</button>
<button onclick="showcss('p2');">Eigenschaft von #p2</button>
</p>

<pre>
Warum kann JS Styleangeben ausserhalb des Elements nicht lesen?

Während die Angabe im TAG problemlos erkannt wird, wird sie aus dem Stylesheet im Head nicht erkannt.
</pre>

</body>
</html>

Gruss Henry

  1. Tach!

    ich wollte mit Javascript den aktuellen Displayzustand eines Elements auslesen. Seltsamerweise und überraschend funktioniert das aber offensichtlich nur wenn die Styleangabe direkt im Element eingebaut ist. Warum?

    Weil style auch nur die direkt im Element angegebenen Eigenschaften liest. Anderenorts angegebene Angaben werden nicht ins Element überführt.

    Warum kann JS Styleangeben ausserhalb des Elements nicht lesen?

    Es kann, mit window.getComputedStyle().

    dedlfix.

    1. Javascript bringt mich immer wieder durcheinander. Instinktiv habe ich

           document.getElementById("p1").getComputedStyle().display
      

      ausprobiert. Manchmal frag ich mich, nach welchen Kriterien die Leute Code verteilen, ich hätte die Funktion an die entsprechende Basis-Klasse für HTML-Elemente gehängt.

      Rolf

      1. @@Rolf b

        Javascript bringt mich immer wieder durcheinander. Instinktiv habe ich

             document.getElementById("p1").getComputedStyle().display
        

        ausprobiert. Manchmal frag ich mich, nach welchen Kriterien die Leute Code verteilen, ich hätte die Funktion an die entsprechende Basis-Klasse für HTML-Elemente gehängt.

        Wie Microsoft das mit currentStyle implementiert hatte, ja.

        LLAP 🖖

        --
        “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
    2. Hallo,

      Weil style auch nur die direkt im Element angegebenen Eigenschaften liest. Anderenorts angegebene Angaben werden nicht ins Element überführt.

      das war mir neu und hätte ich nicht erwartet, danke.

      Es kann, mit window.getComputedStyle().

      OK, getComputedStyle funktioniert auch. Nur wundert mich, warum hier, subjektiv gesehen, die JS-Syntax so seltsam anmutet. Das fängt schon damit an, dass die Variable in der Klammer nicht, wie gewohnt, in Anführungszeichen stehen soll. Was es mir dadurch schwierig macht, einen Weg zu finden das variabel zu lösen.

      • Meine ID lautet #p1, da sollte man meinen:
      • var navobj = window.getComputedStyle(#p1).display;
      • oder:
      • var navobj = window.getComputedStyle('p1').display;
      • oder noch besser:
      • var navobj = window.getComputedStyle('#p1').display;
      • funktionieren tut aber nur:
      • var navobj = window.getComputedStyle(p1).display;

      Jetzt kommt das Problem, in der Funktion möchte ich ja den Wert variabel übermitteln: <button onclick="showcss('p1');">Eigenschaft von #p1</button> und dann innerhalb der Funktion: var navobj = window.getComputedStyle(id).display;

      Das geht aber nicht, hmm... Lösungsvorschlag?

      Gruss Henry

      *Wer sich über die Listenformatierung wundert... Liegt daran, dass hier wieder mal meine Zeilenumbrüche ignoriert werden und ich das damit kompensiere.

      1. Tach!

        OK, getComputedStyle funktioniert auch. Nur wundert mich, warum hier, subjektiv gesehen, die JS-Syntax so seltsam anmutet. Das fängt schon damit an, dass die Variable in der Klammer nicht, wie gewohnt, in Anführungszeichen stehen soll.

        Bitte? Wo stehen denn in Javascript Variablen in Anführungszeichen?

        Was es mir dadurch schwierig macht, einen Weg zu finden das variabel zu lösen.

        Variablen sind dir nicht variabel genug?

        • Meine ID lautet #p1, da sollte man meinen:
        • var navobj = window.getComputedStyle(#p1).display;
        • oder:
        • var navobj = window.getComputedStyle('p1').display;
        • oder noch besser:
        • var navobj = window.getComputedStyle('#p1').display;

        Eine ID ist noch kein Element, und auch keine Variable. Aber das Element zu einer ID bekommst du über getElementById(). Das sollte eigentlich bekannt sein.

        • funktionieren tut aber nur:
        • var navobj = window.getComputedStyle(p1).display;

        Nö, das funktioniert nur, wenn p1 eine Variable ist, die auf dein Element verweist.

        Jetzt kommt das Problem, in der Funktion möchte ich ja den Wert variabel übermitteln: <button onclick="showcss('p1');">Eigenschaft von #p1</button> und dann innerhalb der Funktion: var navobj = window.getComputedStyle(id).display;

        Das geht aber nicht, hmm... Lösungsvorschlag?

        Erstmal das Element zur ID ermitteln.

        *Wer sich über die Listenformatierung wundert... Liegt daran, dass hier wieder mal meine Zeilenumbrüche ignoriert werden und ich das damit kompensiere.

        Code-Auszeichnung geht mit dem Symbol </>. Dann bleibt das formatiert wie es ist und wird sogar noch bunt.

        dedlfix.

        1. Hallo,

          Bitte? Wo stehen denn in Javascript Variablen in Anführungszeichen?

          Eben, es geht ja darum. alert('fester Wert'), alert(variable). Wenn also getComputedStyle(eineVariable) ist, dann verstehe ich das noch weniger, im Selfhtml Beispiel ist es ja auch der Elementenname(Button).

          Was es mir dadurch schwierig macht, einen Weg zu finden das variabel zu lösen.

          Variablen sind dir nicht variabel genug?

          Wenns denn so leicht verständlich wäre... Steh im Moment auf dem Schlauch.

          Eine ID ist noch kein Element, und auch keine Variable. Aber das Element zu einer ID bekommst du über getElementById(). Das sollte eigentlich bekannt sein.

          Nur wie das bei getComputedStyle kombinieren?

          • funktionieren tut aber nur:
          • var navobj = window.getComputedStyle(p1).display;

          Nö, das funktioniert nur, wenn p1 eine Variable ist, die auf dein Element verweist.

          Und wie das funktioniert. Will jetzt nicht wieder den ganzen Code posten, aber probiers erst mal aus:

          <script type="text/javascript">
          function showcss(id)
          {
          // var navobj = document.getElementById(id).style.display;
          var navobj = window.getComputedStyle(p1).display;
          alert(navobj);
          }
          </script>
          

          Erstmal das Element zur ID ermitteln.

          ok, muss ich mich gleich erst mal schlau machen wie das geht.

          *Wer sich über die Listenformatierung wundert... Liegt daran, dass hier wieder mal meine Zeilenumbrüche ignoriert werden und ich das damit kompensiere.

          Code-Auszeichnung geht mit dem Symbol </>. Dann bleibt das formatiert wie es ist und wird sogar noch bunt.

          Müsstest du eigentlich gesehen haben, dass ich das sehr wohl weiß. Es geht aber nicht um eingefügten Code, sondern um normalen Text, der hier oft beim Schreiben wie gewollt erscheint, aber bereits in der Vorschau ohne Zeilenumbrüche. Es hilft dann in der Regel noch mehr Umbrüche zu machen oder eben die Listenalternative.

          Gruss Henry

          1. Hallo

            Wenn also getComputedStyle(eineVariable) ist, dann verstehe ich das noch weniger, im Selfhtml Beispiel ist es ja auch der Elementenname(Button).

            Wie dedlfix bereits sagte, erwartet die Methode getComputedStyle als erstes Argument eine Referenz auf ein Elementobjekt, und mit einer solchen wird die Methode in dem Beispiel auch aufgerufen.

            <button onclick="GetBGColor(this)">Los!</button>
            

            In dieser Zeile wird über das Attribut onclick ein Eventhandler für das Buttonelement registriert.

            Dabei wird die Zeichenkette, die dem Attribut als Wert zugewiesen wurde, zum Körper einer anonymen Funktion geparst, welche dann beim Eintritt des Ereignisses automatisch aufgerufen wird.

            Dies geschieht im Kontext des Elementes, für das der Eventhandler registriert wurde. Das bedeutet, die Kontextvariable this enthält nach dem Aufruf der Funktion eine Referenz auf das Buttonelement.

            Mit dieser Referenz wird dann die zuvor im Scriptelement definierte Funktion GetBGColor aufgerufen, wobei der button genannte Parameter der Funktion mit der übergebenen Referenz initialisiert wird, sodass der Zeiger auf den Button innerhalb der Funktion als lokale Variable zur Verfügung steht.

            Bei dem Aufruf window.getComputedStyle(button) wird also eine Referenz auf den Button übergeben.

            Es sei allerdings erwähnt, dass es sich hier tatsächlich um kein gutes Beispiel handelt, denn diese Art der Ereignisbehandlung über Attribute im Markup ist ganz schlechter Stil.

            Wesentlich besser wäre es, den Button innerhalb des Skripts zu referenzieren, beispielsweise mit der bereits genannten Methode getElementById, oder auch über die Methode querySelector.

            Wenn man den Button dann referenziert hat, kann auf dem Objekt die Methode addEventListener aufgerufen werden, welche als erstes Argument den Namen des Ereignisses erwartet, und als zweites Argument eine Funktion, die beim Ereigniseintritt aufgerufen werden soll.

            <button>Los!</button>
            
            <script>
            
            function getBackgroundColor (element) {
              return window.getComputedStyle(element).backgroundColor;
            }
            
            const button = document.querySelector('button');
            
            button.addEventListener('click', function (event) {
              console.info(getBackgroundColor(button));
            });
            
            </script>
            

            Hier definiere ich die Handlerfunktion direkt bei der Argumentübergabe. Die Ausgabe habe ich aus der Funktion zur Ermittlung der Hintergrundfarbe herausgenommen und in den Eventhandler verlegt. Statt die Methode alert zu verwenden, lasse ich das Ergebnis in der Konsole ausgeben.

            Im Bezug auf das Beispiel wäre es allerdings besser, das Ergebnis als Elementinhalt direkt auf der Seite auszugeben, wobei das passende Element in diesem Fall output wäre.

            const output = document.querySelector('output');
            
            button.addEventListener('click', function (event) {
              output.value = getBackgroundColor(button);
            });
            

            Die bedingte Anweisung in dem Wikibeispiel mit der Eigenschaft currentStyle als Alternative kann übrigens ersatzlos gestrichen werden, ebenso wie die Übergabe des Leerstrings als zweites Argument an die Methode getComputedStyle. Das ist schon lange nicht mehr nötig.

            Nötig wären allerdings Angaben zu Sprache und Viewport …


            Ich habe das Beispiel überarbeitet. ;-)

            Viele Grüße,

            Orlok

            1. Hallo Orlok,

              erstmal vielen Dank für deine sehr ausführliche Antwort. Ich verstehe zwar noch nicht alles davon aber arbeite mich durch.

              Ich habe das Beispiel überarbeitet. ;-)

              Finde ich gut, doch leider funktioniert das Beispiel dort jetzt aber nicht im IE11, FF allerdings schon. Dabei ist mir aufgefallen, dass so einige Beispiele in Selfhtml nicht funktionieren, obwohl sie das eigentlich müssten. Bsp. Autorennen weder IE noch FF.

              Gruss Henry

              1. Nachtrag:

                Doch Autorennen funktioniert, wie ich gerade feststelle, wenn es, wie im genannten Link, Standalone und nicht im Selfhtml-Frame aufgerufen wird.

                1. Hallo Henry,

                  Doch Autorennen funktioniert, wie ich gerade feststelle, wenn es, wie im genannten Link, Standalone und nicht im Selfhtml-Frame aufgerufen wird.

                  Ja, das betrifft leider so einige Beispiele, die im Frickl nicht funktionieren 😟

                  Bis demnächst
                  Matthias

                  --
                  Rosen sind rot.
                2. Servus!

                  Doch Autorennen funktioniert, wie ich gerade feststelle, wenn es, wie im genannten Link, Standalone und nicht im Selfhtml-Frame aufgerufen wird.

                  Einige dieser Beispiele stammen aus der Zeit vor dem Frickl.

                  Die Funktionalität des button-Elements wäre wohl besser mit JavaScript als durch :target realisiert worden. Damals wollte ich beweisen, dass man Animationen ganz ohne JS realisieren kann.

                  Bei JS-Beispielen gibt es eine Fehlerquelle, dass an die id des body gehängte Events nicht im Frickl erkannt werden. Hier müsste ein main-Element eingefügt werden.

                  Generell bitte ich um Rückmeldung im Forum, damit wir diese Beispiele anpassen können.

                  Herzliche Grüße

                  Matthias Scharwies

                  --
                  Es gibt viel zu tun: ToDo-Liste
                3. problematische Seite

                  Servus!

                  Nachtrag:

                  Doch Autorennen funktioniert, wie ich gerade feststelle, wenn es ... Standalone und nicht im Selfhtml-Frame aufgerufen wird.

                  Habe es jetzt genauer anschauen können, und es war wie hier beschrieben:

                  Das id, über das die Steuerung funktionierte, war in:

                  <body id="go">
                  

                  Frickl zieht aber nur alles innerhalb des body in seinen iframe und so fehlte das im Beispiel. Jetzt habe ich es einfach ins main verschoben:

                  <body>
                    <h1>Verwendung von <code>animation-timing-function</code></h1>
                  
                    <main id="go">` 
                  

                  Herzliche Grüße

                  Matthias Scharwies

                  --
                  Es gibt viel zu tun: ToDo-Liste
                  1. problematische Seite

                    @@Matthias Scharwies

                    Jetzt habe ich es einfach ins main verschoben:

                    <body>
                      <h1>Verwendung von <code>animation-timing-function</code></h1>
                    
                      <main id="go">` 
                    

                    IMHO gehört die Überschrift zum Hauptinhalt dazu, also ins main-Element.

                    Das Spiel selbst ist wohl “a complete, or self-contained, composition in a document”, also ein article-Element?

                    <body>
                      <main>
                      <h1>Verwendung von <code>animation-timing-function</code></h1>
                      <article id="go">
                        <h2>Formel 1: Wer ist am Schnellsten?</h2>
                    

                    Das Markup <p><a href="#go">Los!</a> <a href="#reset">Zurück auf Start!</a> ist fehlerhaft. Das sind keine Links, sondern Buttons.

                    LLAP 🖖

                    --
                    “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
                  2. problematische Seite

                    @@Matthias Scharwies

                    Doch Autorennen funktioniert, wie ich gerade feststelle, wenn es ... Standalone und nicht im Selfhtml-Frame aufgerufen wird.

                    Habe es jetzt genauer anschauen können, und es war wie hier beschrieben: […]

                    Das war nur ein Teil des Problems.

                    Jetzt habe ich es einfach ins main verschoben:

                    Das Problem besteht weiterhin: Das Autorennen funktioniert nur standalone (bestenfalls!), nicht im SELFHTML-Frame.

                    „Alle Autos kommen gleichzeitig nach 3 Sekunden ins Ziel!“

                    Welches Ziel? Auch bei Vollbild ist das Ziel nicht im Viewport zu sehen.[1] Die Autos kommen nicht gleichzeitig an der rechten Viewportkante an.

                    LLAP 🖖

                    --
                    “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory

                    1. MacBook Air, 1440 × 900 ↩︎

          2. @@Henry

            Es geht aber nicht um eingefügten Code, sondern um normalen Text, der hier oft beim Schreiben wie gewollt erscheint, aber bereits in der Vorschau ohne Zeilenumbrüche. Es hilft dann in der Regel noch mehr Umbrüche zu machen oder eben die Listenalternative.

            Die Hilfe zur Formatierung der Beiträge ist jetzt hinter dem [?] über dem Einagabefeld versteckt. Ich weiß nicht, ob das gut ist.

            Darin im Abschnitt Absätze und Zeilenumbrüche: „für einen einfachen Zeilenumbruch setzen Sie zwei Leerzeichen an das Zeilenende.“

            LLAP 🖖

            --
            “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
          3. Tach!

            Wenn also getComputedStyle(eineVariable) ist, dann verstehe ich das noch weniger, im Selfhtml Beispiel ist es ja auch der Elementenname(Button).

            Nein, das war kein Elementname. Das muss eine Referenz auf ein Element sein, das in dem Beispiel zufällig in einer gleich benannten Variable referenziert war. Hat man noch keine Referenz, muss man sie sich erst erstellen, woraus auch immer. ID, Element- oder Klassenname plus welcher von den möglicherweise mehreren oder Position im DOM können zum identifizieren genommen. Das kombiniert mit der entsprechenden Funktion, die dir dazu die Elementreferenz gibt, also getElementById() und so weiter. Die wird in einer Variable abgelegt und die Variable dann übergeben.

            • funktionieren tut aber nur:
            • var navobj = window.getComputedStyle(p1).display;

            Nö, das funktioniert nur, wenn p1 eine Variable ist, die auf dein Element verweist.

            Und wie das funktioniert. Will jetzt nicht wieder den ganzen Code posten, aber probiers erst mal aus:

            <script type="text/javascript">
            function showcss(id)
            {
            // var navobj = document.getElementById(id).style.display;
            var navobj = window.getComputedStyle(p1).display;
            alert(navobj);
            }
            </script>
            

            p1 ist in diesem Stück Code nicht definiert. Vielleicht ist es anderenorts global definiert, vielleicht sitzt du da aber auch nur einer Besonderheit eines Browsers auf, der automagisch aus Elementen mit IDs eine gleichnamige Variable erstellt, was wohl meines Wissens kein Standard ist und dir anderenbrowsers nicht zur Verfügung steht. Nimm das statt der auskommentierten Zeile:

            var p1 = document.getElementById(id);
            

            dedlfix.

            1. @@dedlfix

              Nein, das war kein Elementname. Das muss eine Referenz auf ein Element sein, das in dem Beispiel zufällig in einer gleich benannten Variable referenziert war. Hat man noch keine Referenz, muss man sie sich erst erstellen, woraus auch immer. […]

              p1 ist in diesem Stück Code nicht definiert. Vielleicht ist es anderenorts global definiert, vielleicht sitzt du da aber auch nur einer Besonderheit eines Browsers auf, der automagisch aus Elementen mit IDs eine gleichnamige Variable erstellt

              IIRC tut der IE genau das. Macht Edge das auch noch?

              was wohl meines Wissens kein Standard ist und dir anderenbrowsers nicht zur Verfügung steht.

              Wer entwickelt seine Webseiten denn mit IE? Und wer ausschließlich mit IE, ohne in anderen Browsern zu testen?

              LLAP 🖖

              --
              “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
              1. IIRC tut der IE genau das. Macht Edge das auch noch?

                Ja, macht er. Chrome und Firefox übrigens auch

                Wer entwickelt seine Webseiten denn mit IE?

                Ich. Weil ich muss und weil's immer noch der Standardbrowser in meinem Laden ist (unsere Terminalserver operieren noch auf Windows Server 2008 R2, also Win7).

                Und wer ausschließlich mit IE, ohne in anderen Browsern zu testen?

                Naja, das nicht. Firefox ist unser offizieller Alternativbrowser und mit Chrome teste ich auch noch. Aber ich baue normalerweise nichts für's Wilde Weiter Web, daher brauche ich nicht mehr...

                Rolf

        • Meine ID lautet #p1, da sollte man meinen:
        • var navobj = window.getComputedStyle(#p1).display;
        • oder:
        • var navobj = window.getComputedStyle('p1').display;
        • oder noch besser:
        • var navobj = window.getComputedStyle('#p1').display;

        NEIN. Die ID des <p> Elements lautet nicht #p1. Sie lautet p1. Das # verwendest Du nur in CSS-Selektoren, um ein Symbol als ID zu kennzeichnen.

        Dass der Browser für Elemente mit ID eine globale Variable mit gleichem Namen anlegt, ist in HTML 4 non-standard gewesen. Aber im IE war es üblich, andere Browser sind nachgezogen, und in HTML 5 versuchte man, es zum Standard zu erheben, mit kontroversen Reaktionen. In älteren Postings auf StackOverflow habe ich Hinweise gesehen, dass die WhatWG diese Absicht hatte, finde aber im aktuellen Standard-Text von WhatWG auf die Schnelle keinen Hinweis mehr darauf.

        Definitiv standardkonform sind diese beiden Techniken:

         document.getElementById('p1')  - seit ewigen Zeiten
         document.querySelector('#p1')  - seit Chrome 1, FF 3.5, IE8, Opera 10, Safari 3.2
        

        Bei querySelector schreibst Du das # hin, weil dort ein CSS Selektor erwartet wird und nicht nur eine nackige ID.

        Den Rückgabewert von einer dieser beiden Funktionen kannst Du in einer Variablen - z.B. p1 - speichern oder direkt an window.getComputedStyle() übergeben.

        Rolf

        1. Hallo,

          danke an alle, alles sehr informativ und hilfreich.

          Fazit:

          1. JS kann kann nur innerhalb Elemente auslesen.

          2. getComputedStyle(Bsp. funktioniert jetzt auch im IE) ist die Alternative um übergreifend abzufragen.

          3. Browser deklarieren Elementen-ID automatisch zu Variablen.(Wissenswert, aber sollte man sich nicht drauf verlassen)

          Der Vollständigkeit halber nochmal:

          <script type="text/javascript">
          function showcss(id)
          {
          var obj =  document.getElementById(id);
          
          /* ***********************
          funktioniert zwar auch, aber nur weil Browser die ID automatisch
          zur Variablen deklarieren...ob das sinnvoll ist?
          
          https://forum.selfhtml.org/self/2017/jun/10/js-kann-styleangeben-nicht-lesen/1696217#m1696217
          ********************************/
          // var navobj = window.getComputedStyle(p1).display;
          
          // Besser so... getComputedStyle erwartet wohl eine Objektreferenz
          var navobj = window.getComputedStyle(obj).display;
          
          alert(navobj);
          }
          </script>
          

          Gruss
          Henry