Eine Funktion, mit der man browserunabhängig ein Stylesheet seines Dokuments
ändert, habe ich mit cssRule() bereits
veröffentlicht. Das funktioniert logischerweise nur, wenn es bereits ein
Stylesheet mit einer CSS-Regel gibt, die man ändern kann.
Aber natürlich bieten die DHTML-fähigen Browser auch JavaScript-Methoden
an, um dynamisch neue Stylesheets, bzw. neue Regeln in diesen anzulegen. Aber
leider, wer hätte das gedacht >;-), unterscheiden sich
die Methoden vom Internet Explorer und dem Rest der Welt. In einzelnen sind hierfür
gedacht:
createElement() um HTML-Elemente im Allgemeinen und
eben auch STYLE-Elemente im Besonderen anzulegen (die dann z.B. mit
appendChild() im Dokumenten-Baum hinzugefügt werden).
addRule() im IE-DOM, bzw. insertRule() im
W3C-DOM, um in einem existierenden Stylesheet eine neue Regel zu
ergänzen.
Soweit die einfache Theorie, was sagt aber die mal wieder problematische
Praxis? Die sagt, daß z.B. bei dieser offiziellen Vorgehensweise Browser mit
der KHTML-Engine leider einen Bug haben können, oder daß im IE mit
createElement() erstellte Stylesheets nicht sofort zur Verfügung stehen
(der IE "bevorzugt" sein proprietäres createStyleSheet()), oder ...
Aber kein Problem: Aus Sicht des DOM ist der Inhalt eines STYLE-Elements,
also die CSS-Regeln selbst, ja ohnehin nur ein simpler Textknoten. Warum
also nicht einfach createTextNode() verwenden? Das klappt auch super
- außer im Internet Explorer. Der IE besteht auf seinem addRule().
Also doch Anlaß genug, das unterschiedliche Browserverhalten durch eine
optimierte Funktion zu vereinheitlichen.
Der Funktionsaufruf:
addStyle([rules[,target]])
Der 1. (optionale) Parameter rules ist ein String mit einer oder
mehreren neuen CSS-Regeln in der Form selector { property:value; },
also z.B.: body { color: black; background-color: red; } div {
border: 1px solid black; }
Achtung: Da der IE bei dynamischen Styles den Umgang mit gruppierten
Selektoren prinzipiell nicht beherrscht, teilt addStyle() im IE
gruppierte Selektoren in ihre Einzelselektoren auf! Aus z.B. html, body {
font-size: 120%; } wird also im IE html {
font-size: 120%; } body { font-size: 120%; }!
Die anderen Browser haben hingegen tatsächlich einen gruppierten
Selektor (natürlich mit all den Unterschieden, die diese Browser
dann dennoch hier machen - s. auch cssRule()).
Der 2. (optionale) Parameter target bestimmt das zu ergänzende
Stylesheet. Mögliche Werte für target sind:
Eine Zahl, die die Nummer des zu ergänzenden STYLE-Elements
definiert (0 für das erste STYLE-Element, 1
für das zweite, usw. Die neuen Regeln werden dann diesem Stylesheet
hinzugefügt. Bei negativen Zahlen, wird von hinten gezählt
(-1 für das letzte STYLE-Element, -2 für
das vorletzte, usw.). Wird zu der übergebenen Zahl kein passendes
STYLE-Element gefunden, so wird das am nächstenliegende, also das
erste oder das letzte STYLE-Element ergänzt.
Ein String mit einer Medientyp-Angabe (screen, print,
etc.). Es wird eine neues STYLE-Element für diesen Medientyp erzeugt.
Wird kein target-Parameter übergeben, so wird ein neues,
allgemeines Stylesheet angelegt (also gültig für alle Medien).
Die Funktion gibt als Ergebnis das Objekt des erzeugten bzw. bearbeiteten
STYLE-Elements zurück, oder null falls die Aktion nicht
durchgeführt werden konnte.
Beispiele:
addStyle("body { font-size: 120%; }",0); fügt am Ende des
1. STYLE-Elements die angegebene Regel ein, bzw. erstellt ein neues
Stylesheet, falls es nicht existiert.
alert(addStyle("body { font-size: 120%; }",0).innerHTML);
dito, jedoch wird anschließend der Inhalt des (ergänzten oder
neuen) STYLE-Elements in einer Alert-Box ausgegeben.
addStyle("body { font-size: 120%; }","print"); fügt ein
neues Drucker-Stylesheet mit der Regel ein.
addStyle("body { font-size: 120%; } p { text-align: justify; }");
fügt ein neues Stylesheet mit 2 Regeln ein (gültig für alle Medien).
addStyle(); fügt ein neues, leeres Stylesheet ein
(gültig für alle Medien).
Achtung: Leere Stylesheets werden beim Safari & Konqueror ggf.
nicht in die styleSheets-Collection aufgenommen!
addStyle("body { font-size: 120%; }",9999); fügt im
letzten STYLE-Element die angegebene Regel ein, davon ausgehend,
daß es nicht mehr als 10000 STYLE-Elemente gibt. ;-)
addStyle("body { font-size: 120%; }",-1); fügt im
letzten STYLE-Element die angegebene Regel ein, selbst falls es mehr
als 10000 STYLE-Elemente geben sollte. ;-))
if(!cssRule("body@print","font-size","12pt")) { addStyle("body { font-size: 12pt;","print"); }
ändert mittels cssRule() im Drucker-Stylesheet
die Textgröße des Elements BODY auf 12pt, oder erstellt
ein neues Drucker-Stylesheet mit dieser Regel, falls keine existierende Regel
geändert werden konnte. Für diesen Zweck steht auch die Funktion setCssStyle()
zur Verfügung:
A cross-browser function to change a documents style sheet has been
published by me as cssRule().
Obviously this function can only be used if an appropriate CSS rule already
exists for changing.
Of course, DHTML compatible browsers have JavaScript methods to add new style
sheets (createElement()) and CSS rules (insertRule())
dynamically. But again: The IE (with a delay at createElement()
and needing addRule() for new rules) differs from the rest of the
world, whith KHTML browsers having a nasty bug at insertRule().
The solution is this cross-browser function using proprietary
createStyleSheet() & addRule() on IE and
createElement() & createTextNode() on all other
browsers - a little workaround which also works perfectly on buggy Konquerors.
The function call:
addStyle([rules[,target]])
The 1st (optional) parameter rules is a string containing one or
more CSS rules to add specified as selector { property:value; },
i.e.: body { color: black; background-color: red; } div {
border: 1px solid black; }
The 2nd (optional) parameter target determines the style sheet
to add the rules. Possible values are:
An integer defining the number of the STYLE element (0 for
the 1st STYLE element, 1 for the 2nd and so on). New rules
will be added at the end of that style sheet. Negative numbers will
cause counting backwards (-1 for the last STYLE element, ...).
If there is no matching STYLE element, the next near by will be used (the
first or the last STYLE element).
A string with a media type (screen, print,
...). A new STYLE element of that media type will be created.
With no target at all, a new common style sheet (used by
all medias) will be created.
The function returns the object of the created or used STYLE element or null
on error.
Examples:
addStyle("body { font-size: 120%; }",0); adds the rule
at the end of the 1st STYLE element or creates a new STYLE element with that
rule if no STYLE element exists.
alert(addStyle("body { font-size: 120%; }",0).innerHTML);
the same, but showing the contents of the STYLE element in an alert box
afterwards.
addStyle("body { font-size: 120%; }","print"); creates
a new printer style sheet with that rule.
addStyle("body { font-size: 120%; } p { text-align: justify; }");
creates a new style sheet with 2 rules (used by all medias).
addStyle(); creates a new, empty style sheet (used by all medias).
Attention: Empty style sheets are probably ignored by Safaris & Konquerors
styleSheets collection!
if(!cssRule("body@print","font-size","12pt")) { addStyle("body { font-size: 12pt;","print"); }
changes the font size at the BODY element of a printer style sheet using
cssRule() to 12pt or
creates a new printer style sheet if no existing rule could be changed.
Korrektur: Workaround für den IE eingebaut, weil er bei addRule() nicht mit einem "leerem Stil" umgehen kann.
28.07.2007:
Erweiterung: Es können jetzt mehrere Regeln anstatt nur einer übergeben werden, und Workaround für IE-Verhalten bei gruppierten Selektoren eingebaut.
31.05.2007:
Korrektur: Im Download-Script (nicht in der intern von dieser Website benutzen Version) war versehentlich eine Codezeile doppelt, und die Regel wurde im IE zweimal angelegt (was prinzipiell ärgerlich, technisch aber unproblematisch ist).