MudGuard: style-Element erzeugen per Script

Hi,

ich versuche, ein style-Element per Javascript zu erzeugen.

  
var colors = new Array( "red", "blue", "yellow", "green", "teal", "fuchsia", "silver", "gold" );  
function restyle()  
{  
    var col = colors[Math.floor(Math.random() * colors.length)];  
    var mytext = "body { background-color: " + col + "; }";  
    var textNode = document.createTextNode(mytext);  
  
    var headElem = document.documentElement.firstChild;  
  
    var styleElem = document.createElement("style");  
    styleElem.setAttribute("type", "text/css");  
    styleElem.appendChild(textNode);                //hier krachts im IE  
  
    headElem.appendChild(styleElem);                //hier krachts im IE  
}  

Das funktioniert in Opera 7.53 und 8.01 sowie in Geckos FF 1.0.6 und Moz 1.7.3 wunderbar.
Im IE bekomme ich beim Einhängen des style-Elements in den Head oder beim Einhängen des Textknotens in das style-Element (je nachdem, welche der beiden Aktionen zuerst stattfinden) eine Fehlermeldung:
Fehler: Unerwarteter Aufruf oder Zugriff

Wie kann ich das im IE hinbekommen?

Da im Echt-Einsatz User-Eingaben in das Stylesheet mit reinsollen (anstelle der jetzt nur zufällig gesetzten Farbe), kann ich das style-Element nicht beim Seitenaufbau per document.write schreiben.

headElem und styleElem enthalten die korrekten Elemente, das hab ich schon überprüft.

cu,
Andreas

--
Warum nennt sich Andreas hier MudGuard?
Schreinerei Waechter
Fachfragen per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
  1. Tag MudGuard.

    ich versuche, ein style-Element per Javascript zu erzeugen.
    [...]
    Im IE bekomme ich beim Einhängen des style-Elements in den Head oder beim Einhängen des Textknotens in das style-Element (je nachdem, welche der beiden Aktionen zuerst stattfinden) eine Fehlermeldung:

    Wenn ich das MSDN richtig lese, kannst du appendChild nicht auf ein style-Element anwenden:
    http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/appendchild.asp
    (unter "Applies To", da ist style nicht aufgeführt)

    Mit einem (hier völlig schwachsinnigen) DIV geht's. Du wirst wohl das style-Objekt verwenden müssen.

    Siechfred

    --
    Ihr nehmt mich auf eigene Gefahr ernst.
    1. Hi,

      Wenn ich das MSDN richtig lese, kannst du appendChild nicht auf ein style-Element anwenden:

      Was für ein Schwachsinn.
      Wie kommen die auf die saudumme Idee, style-Elemente hier anders als andere Elemente zu behandeln?

      Mit einem (hier völlig schwachsinnigen) DIV geht's. Du wirst wohl das style-Objekt verwenden müssen.

      style-Objekt? Du meinst, für jedes Element, das durch einen der Selektoren ggf. betroffen ist, einzeln sämtliche Eigenschaften setzen?
      Sozusagen das ganze Parsen des HTML-Baums sowie des Stylesheets nochmal nachprogrammieren?

      cu,
      Andreas

      --
      Warum nennt sich Andreas hier MudGuard?
      Schreinerei Waechter
      Fachfragen per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
      1. Hallo Andreas,

        es könnte auch mit der Reihenfolge von setAttribute()-Methode und Einhängen in den Elementbaum zu tun haben.

        http://forum.de.selfhtml.org/archiv/2005/7/t111727/#m704488

        Gruß Gernot

        1. Hi,

          es könnte auch mit der Reihenfolge von setAttribute()-Methode und Einhängen in den Elementbaum zu tun haben.

          hat es in diesem Fall aber nicht.

          Egal ob mit oder ohne Attribut, egal ob Attribut am Anfang nach dem Kreieren des style-Elements oder nach dessen Einhängen in den head oder wann auch immer, es geht nicht.

          mit innerHTML oder innerText statt appendChild() krieg ich es auch nicht hin, gibt auch jeweils so detaillierte Fehlermeldungen wie die erwähnte oder
          Unbekannter Laufzeitfehler

          Drecksbrowser!

          cu,
          Andreas

          --
          Warum nennt sich Andreas hier MudGuard?
          Schreinerei Waechter
          Fachfragen per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
      2. Hallo,

        Du meinst, für jedes Element, das durch einen der Selektoren ggf. betroffen ist, einzeln sämtliche Eigenschaften setzen?
        Sozusagen das ganze Parsen des HTML-Baums sowie des Stylesheets nochmal nachprogrammieren?

        In dem Fall nähme man http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/addrule.asp, mit dem man direkt eine CSS-Regel setzen kann.
        http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/createstylesheet.asp
        http://www.styleassistant.de/tips/tip20.htm
        http://www.styleassistant.de/tips/beispiel20.htm

        Mathias

        1. P.S. Gecko kann das auch (nur anders, weil standardkonform), das Ganze nennt sich DOM 2 Style bzw. CSS. Speziell insertRule, wobei Gecko kein createStylesheet kennt, in DOM 2 Style ist das anders geregelt, dort muss man style- bzw. link-Elemente einfügen.
          Wenn aber schon ein Stylesheet eingebungen ist, kann man dem eine Regel hinzufügen, somit fällt createStylesheet und createElement weg.
          Opera ist also derjenige, der einer Extrawurst bedarf. :)

          Mathias

          1. Hi,

            Opera ist also derjenige, der einer Extrawurst bedarf. :)

            Meine Rede!

            Gruß, Cybaer

            --
            Hinweis an Fragesteller: Fremde haben ihre Freizeit geopfert, um Dir zu helfen. Helfe Du auch im Archiv Suchenden: Beende deinen Thread mit einem "Hat geholfen" oder "Hat nicht geholfen"!
          2. Ein umfassendes Beispiel, das die verschiedenen Möglichkeiten erläutert:

              
            function addStyle (selector, declarations) {  
             if (document.styleSheets && document.styleSheets.length > 0) {  
              // alert("use styleSheets[0]");  
              if (document.styleSheets[0].insertRule) {  
               new_rule_number = document.styleSheets[0].insertRule(selector + " {" + declarations + "}", document.styleSheets[0].cssRules.length);  
               if (document.styleSheets[0].cssRules[new_rule_number].cssText.length > 0) {  
                alert("added with styleSheets[0].insertRule");  
                return true;  
               } else {  
                alert("styleSheets[0].insertRule failed - using Konqueror?");  
               }  
              } else if (document.styleSheets[0].addRule) {  
               document.styleSheets[0].addRule(selector, declarations);  
               alert("added with styleSheets[0].addRule");  
               return true;  
              }  
             }  
             if (document.createStyleSheet) {  
              // alert("use createStyleSheet");  
              var stylesheet = document.createStyleSheet();  
              if (stylesheet && stylesheet.addRule) {  
               stylesheet.addRule(selector, declarations);  
               alert("added with createStyleSheet / addRule");  
               return true;  
              }  
             }  
             if (document.createProcessingInstruction && document.insertBefore) {  
              //alert("use createProcessingInstruction");  
              var inserted_node;  
              try {  
               var pi = document.createProcessingInstruction("xml-stylesheet", "type='text/css' href='test.css'");  
               inserted_node = document.insertBefore(pi, document.documentElement);  
              } catch (e) {  
               alert("failed adding with createProcessingInstruction. probably not an XHTML document");  
              }  
              if (pi && inserted_node && pi.sheet) {  
                alert("delay necessary");  
                pi.sheet.insertRule(selector + " {" + declarations + "}", 0);  
                alert("added with createProcessingInstruction / insertRule");  
                return true;  
              }  
             }  
             if (document.getElementsByTagName && document.getElementsByTagName("style").length > 0) {  
              // alert("use getElementsByTagName / appendChild");  
              var style_elements = document.getElementsByTagName("style");  
              var text_node = document.createTextNode(selector + " {" + declarations + "}");  
              style_elements[style_elements.length - 1].appendChild(text_node);  
              alert("added with getElementsByTagName / appendChild");  
              return true;  
             }  
             if (document.getElementsByTagName && document.createElement) {  
              // alert("use createElement / appendChild");  
              var style_element = document.createElement("style");  
              style_element.setAttribute("type", "text/css");  
              var text_node = document.createTextNode(selector + " {" + declarations + "}");  
              style_element.appendChild(text_node);  
              var head_elements = document.getElementsByTagName("head");  
              if (head_elements && head_elements.length == 1) {  
               head_elements[0].appendChild(style_element);  
               alert("added with createElement / appendChild");  
               return true;  
              }  
             }  
             return false;  
            }  
            
            

            Leider funktioniert die DOM-2-CSS-Variante nicht im Konqueror 3.4, weil es insertRule dort zwar gibt, er aber schlichtweg nichts tut, also die Regel nicht anwendet. Sogar cssRules.length wird erhöht. Man kann nur an einem Punkt sehen, dass die Regel nicht eingefügt wird: cssText der neu erzeugten Rule ist leer (String mit Länge 0). Ansonsten stimmt aus der Sicht von document.styleSheets alles (selectorText, rule.style.cssText, rule.style[X], rule.style.getPropertyValue(rule.style[X])). Aus der Sicht des Elementenbaums sieht man, dass sich der Inhalt des style-Elements nicht ändert.

            Der Test mit dem Einfügen der Processing Instruction sollte auch bei XML-Dokumenten funktionieren, die nicht XHTML sind. Und es sollte der bevorzugte Weg bei XHTML sein, aber Mozilla braucht eine kleine Verzögerung zwischen dem Einfügen der PI und dem insertRule, ansonsten bricht er mit einer DOM-Exception ab. Opera kann auch createProcessingInstruction fälschlicherweise im HTML-Modus, aber kann DOM 2 CSS (pi.sheet). Konqueror löst eine DOM-Exception nicht beim createProcessingInstruction, aber beim insertBefore darauf aus (HIERARCHY_REQUEST_ERR) - sowohl in HTML- als auch in echten X(H)TML-Dokumenten.

            Mathias

          3. Hi,

            (irgendwie ist meine Antwort von gestern nachmittag verschwunden ...)

            P.S. Gecko kann das auch (nur anders, weil standardkonform)

            Das hieße, daß es im Code 2 Zweige gäbe - einmal für Geckos, einmal für IE.

            Opera ist also derjenige, der einer Extrawurst bedarf. :)

            Also 3 Wege.

            Super. Und das nur, weil der IE zu dämlich ist, einem Element einen Textknoten hinzuzufügen.

            cu,
            Andreas

            --
            Warum nennt sich Andreas hier MudGuard?
            Schreinerei Waechter
            Fachfragen per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
            1. Hi,

              Das hieße, daß es im Code 2 Zweige gäbe - einmal für Geckos, einmal für IE.

              Ja, aber prinzipiell identisch, nur mit etwas anderer Syntax. Das ist leicht zu handhaben.

              Super. Und das nur, weil der IE zu dämlich ist, einem Element einen Textknoten hinzuzufügen.

              Nur weil der Opera zu dumm ist, dafür die DOM-Funktionen bereitzustellen, die dafür gedacht sind. Wieso gibt es die denn, wenn man es ohnehin mit "Standardmitteln" erledigen sollte? ;-)

              Gruß, Cybaer

              PS: Natürlich ärgerlich, daß sich W3C- & MS-Syntax unterscheiden, aber in diesem Fall war wohl MS diejenigen, die das innovativ und zuerst umgesetzt haben ...

              --
              Hinweis an Fragesteller: Fremde haben ihre Freizeit geopfert, um Dir zu helfen. Helfe Du auch im Archiv Suchenden: Beende deinen Thread mit einem "Hat geholfen" oder "Hat nicht geholfen"!
      3. Tag MudGuard.

        style-Objekt? Du meinst, für jedes Element, das durch einen der Selektoren ggf. betroffen ist, einzeln sämtliche Eigenschaften setzen?

        Ähm, ich dachte, dass es nur um das body-Element geht, da täte es ein

        document.getElementsByTagName('body')[0].style.backgroundColor = deineFarbe

        auch. Ansonsten ist natürlich molilys Vorschlag der bessere Weg.

        Siechfred

        --
        Ihr nehmt mich auf eigene Gefahr ernst.
        1. Hallo,

          Ähm, ich dachte, dass es nur um das body-Element geht, da täte es ein

          document.getElementsByTagName('body')[0].style.backgroundColor = deineFarbe

          Ich werde nie verstehen, warum man getElementsByTagName benutzt, um das body-Element anzusprechen - es gibt ja document.body. ;)

          Mathias

          1. Hi,

            Ich werde nie verstehen, warum man getElementsByTagName benutzt, um das body-Element anzusprechen - es gibt ja document.body. ;)

            Einheitliche Syntax! :-)

            Gruß, Cybaer

            --
            Hinweis an Fragesteller: Fremde haben ihre Freizeit geopfert, um Dir zu helfen. Helfe Du auch im Archiv Suchenden: Beende deinen Thread mit einem "Hat geholfen" oder "Hat nicht geholfen"!
    2. hi,

      Du wirst wohl das style-Objekt verwenden müssen.

      das wird aber vermutlich recht unkomfortabel, sobald damit nicht nur spezielle elemente formatierungen erhalten sollen, sondern beispielsweise auch css-klassen dynamisch hinzugefügt werden sollen.

      vielleicht wäre dafür innerHTML eine alternative - da steht nämlich unter applies to auch style aufgeführt.
      (bei innerText komischerweise wieder nicht; dabei enthält <style> als kindelement doch lediglich einen textknoten, aber kein weiteres HTML. das ist wohl wieder mal eine der stellen, an denen man microsoft nicht verstehen muss ...)

      gruß,
      wahsaga

      --
      /voodoo.css:
      #GeorgeWBush { position:absolute; bottom:-6ft; }
      1. Hi,

        das wird aber vermutlich recht unkomfortabel, sobald damit nicht nur spezielle elemente formatierungen erhalten sollen, sondern beispielsweise auch css-klassen dynamisch hinzugefügt werden sollen.

        richtig.

        vielleicht wäre dafür innerHTML eine alternative - da steht nämlich unter applies to auch style aufgeführt.

        Nein. Steht auch dort, weiter oben im Text: für style (und ein paar andere) readonly.

        (bei innerText komischerweise wieder nicht; dabei

        enthält <style> als kindelement doch lediglich einen textknoten, aber kein weiteres HTML. das ist wohl wieder mal eine der stellen, an denen man microsoft nicht verstehen muss ...)

        Mit innerText geht es (ausprobiert) genausowenig wie mit innerHTML.

        cu,
        Andreas

        --
        Warum nennt sich Andreas hier MudGuard?
        Schreinerei Waechter
        Fachfragen per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
  2. Hallo Andreas,

    Das funktioniert in Opera 7.53 und 8.01

    würde mich jetzt nur mal interessieren, ob Du im Opera auch eine Auswirkung erzielst - und wenn ja, wie. _Genau_ das Gleiche hab ich nämlich auch schon vergeblich versucht und im OP keine Reaktion. Dein Script funktioniert auch nur in meinem FF. Übrigens kann man im IE etwas erreichen, wenn man das StyleSheet einfach im Body einsetzt, ist halt IE ;-)

    Ich habe von solchem Unfug erstmal Abstand genommen und erledige momentan alles über Styleobjekte der HTML-Nodes. Das ist natürlich erheblich aufwändiger, funktioniert aber in IE, FF und OP.

    Gruß, Andreas

    --
    SELFFORUM - hier werden Sie geholfen,
    auch in Fragen zu richtiges Deutsch
    1. Hi,

      Das funktioniert in Opera 7.53 und 8.01
      würde mich jetzt nur mal interessieren, ob Du im Opera auch eine Auswirkung erzielst -

      Das steht doch da, daß es funktioniert.
      Würde es keine Auswirkung haben, würde ich nicht von "funktioniert" sprechen.

      und wenn ja, wie.

      Genau mit der genannten Funktion. Dazu im body noch ein <input type="button" onclick="restyle()">. Fertig.
      Gerade nochmal hier zu Hause ausprobiert.

      _Genau_ das Gleiche hab ich nämlich auch schon vergeblich versucht und im OP keine Reaktion. Dein Script funktioniert auch nur in meinem FF.

      Ist in Deinem Opera Javascript deaktiviert?

      Übrigens kann man im IE etwas erreichen, wenn man das StyleSheet einfach im Body einsetzt, ist halt IE ;-)

      Pervers.
      Funktioniert aber bei mir nicht.
      Wenn ich headElem in meinem Script statt mit document.documentElement.firstChild auf document.body setze, bekomme ich dieselben Laufzeitfehler, jeweils beim Versuch, den Text bzw. Textnode ins style-Element reinzubekommen.

      cu,
      Andreas

      --
      Warum nennt sich Andreas hier MudGuard?
      Schreinerei Waechter
      Fachfragen per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
      1. Ist in Deinem Opera Javascript deaktiviert?

        jaja, und mein Rechner war abgeschaltet ;-) - nein es ist aktiviert. Mein JS-Programm, das ähnlichen Firlefanz macht funktioniert ja wunderbar im OP. Der OP hat bei meinen damaligen Versuchen auch den Style-Bereich korrekt eingesetzt, aber eben optisch keine Auswirkungen gezeigt. Version 7.54

        Der IE-Zweig unten funktioniert übrigens in meinem OP. Das kann man testen, wenn man den auskommentierten Teil bezüglich OP wieder einseztz - dann geht es nicht mehr.

        Übrigens kann man im IE etwas erreichen, wenn man das StyleSheet einfach im Body einsetzt, ist halt IE ;-)
        Pervers.

        ja, aber soll das Perverse nicht gerade Lust bereiten? ;-)

        Funktioniert aber bei mir nicht.

        mach's doch einfach mit innerHTML. Man muß die S/M-Szene mit ihren eigenen Mitteln ködern ;-)

        function restyle()
        {
            var col = colors[Math.floor(Math.random() * colors.length)];
            var mytext = "body { background-color: " + col + "; }";
            var textNode = document.createTextNode(mytext);

        if(document.all) // && !window.opera
            {
                var style1 = '<style type="text/css">';
                var style2 = '</style>';
                document.body.innerHTML += style1+mytext+style2;
            }
            else
            {
                var headElem = document.documentElement.firstChild;
                var styleElem = document.createElement("style");
                styleElem.setAttribute("type", "text/css");
                styleElem.appendChild(textNode);                //hier krachts im IE
                headElem.appendChild(styleElem);                //hier krachts im IE
            }
        }

        da wird jetzt zwar immer ein neuer Style-Bereich eingesetzt, aber das kannst Du auch wegproggen. Da hab ich jetzt keine Lust zu. Jedenfalls funktionierts.

        So, und jetzt beschreib doch mal, was das für ein Programm wird :-)

        Gruß, Andreas

        --
        SELFFORUM - hier werden Sie geholfen,
        auch in Fragen zu richtiges Deutsch