Coding-Schatzkästlein
Kleine Tips & Scripts zum Webdesign
Start > DHTML > CSS-Regeln

DHTML: CSS-Regeln (& Stylesheets) mit JavaScript auslesen & ändern
(styleSheets mit rules/cssRules & cssText browserübergreifend nutzen)

Zusammenfassung

Name:  CSS Rule
Aufgabe:  Browserübergreifendes (& medienabhängiges) auslesen und manipulieren von internen & externen CSS-Regeln & -Stylesheets.
Benötigt:  JavaScript 1.5 (gesichert, nicht gesichert für JavaScript 1.0)
Beispiel:  cssRule(".alert","color","red")
cssRule("#head","","font-size: 2em; font-weight: bold;")
cssRule(".content@print","font-size","12pt")
alert(cssRule("0/0")) Testseite 1
Testseite 2

Download:  cssrule.zip

English summary at end of page!

Damit HTML-Elemente unterschiedlich aussehen können, dienen Cascading Style Sheets, kurz: CSS. In einem Stylesheet werden die Regeln definiert, wie das HTML-Markup darzustellen ist. Jede Regel besteht aus mindestens einem Selektor (z.B. #box für das Element mit der ID "box") und einer beliebigen Zahl "Eigenschaft:Wert;"-Paaren (z.B. border:0;).

In DynamischemHTML, der Verbindung von HTML, JavaScript und CSS, ist es nun üblich, den Eigenschaften der HTML-Elemente mittels JavaScripts style direkt neue Werte zuzuweisen (z.B. document.getElementById("box").style.border="0";) und dann mit style auch wieder auszulesen, oder aber das HTML-Element mit className insgesamt einer neuen Klasse (für die andere Stile gelten) zuzuordnen (z.B. document.getElementById("box").className="important";), bzw. dann mit currentStyle auf dem Internet Explorer und getComputedStyle() auf W3C-kompatiblen Browsern den gültigen Stil auszulesen (was auch über die schon unterschiedliche Syntax der Browser hinaus nicht ganz unproblematisch ist - aber das ist ein anderes Thema).

Weniger bekannt ist hingegen die Möglichkeit, nicht den HTML-Elementen sondern den CSS-Regeln neue Eigenschaften und Werte zuzuweisen, denn JS hat auch Zugriff auf das DOM CSS und kann somit mit einer Anweisung das Aussehen beliebig vieler HTML-Elemente ändern! Eigentlich verblüffend, denn schließlich ist dies so, als wenn CSS nur ID-Selektoren kennen würde (z.B. #box für <div id="box">), nicht jedoch die so mächtigen Klassen- oder Tag-Selektoren (z.B. .box für <div class="box"> oder p für <p>), die gleich für eine Vielzahl von HTML-Elementen stilgebend sind.
Die hier vorgestellte Funktion erlaubt es, bestehende CSS-Regeln & -Stile abzufragen bzw. zu ändern (eine Funktion, um einfach mit JavaScript komplett neue Stylesheets und CSS-Regeln zu erzeugen, habe ich als addStyle() veröffentlicht).

Selbst bei Änderung an vielen Elementen ist es üblich, diese mittels JavaScript einzeln durchzugehen (oder sie von Bibliotheken wie jQuery durchgehen zu lassen), und jeweils die gewünschte Eigenschaft oder zumindest den Klassennamen zu verändern. Wenn man hingegen einfach die CSS-Regel selbst ändert, ergeben sich folgende Vorteile:

  • Mit nur einer Anweisung können alle HTML-Elemente abgehandelt werden, für die der Selektor dieser Regel zutrifft (1 Änderung / x-fache Wirkung - egal ob 10 oder 10000 Elemente davon betroffen sind).
  • Es lassen sich auch viele Stile auf einen Schlag ändern, indem man eine komplette Regel mit mehreren Stilen ändert, anstatt jeden zu ändernden Stil einzeln.
  • Der Stil der HTML-Elemente kann geändert werden, bevor diese HTML-Elemente überhaupt existieren, also noch vor dem Beginn des BODY-Tags (herkömmlich kann dies nur nachträglich geschehen, z.B. im onLoad-Event, nachdem die HTML-Elemente bereits existent oder gar sichtbar waren).
    Anmerkung: Dies gilt leider nicht für die allerersten Safari-Browser. Sie können erst nach dem Laden des Dokuments auf die Stylesheets zugreifen. Die aktuellen Safari-Browser (>3) sind hingegen standardkonform und schaffen das problemlos.
  • Anders als bei der direkten Stiländerung (die für alle Ausgabemedien gültig ist), lassen sich hier gezielt für einzelne Geräte Stile auslesen & ändern. D.h., für die Druckausgabe andere Stile, als für die Bildschirmausgabe, oder Handhelds, oder ...
    Falls man also z.B. das Layout dynamisch auf die Browsergröße anpassen möchte, ist es also über diesen Weg möglich (und auch sehr sinnvoll), wirklich nur das Bildschirmlayout zu ändern, während z.B. das Drucklayout unverändert bleibt.
  • Ebenfalls lassen sich Pseudoformate (z.B. die Pseudoklasse :hover oder das Pseudoelement :first-letter) nur auf diesem Weg auslesen & ändern.
  • Außerdem: Sämtliche Stile die innerhalb von JavaScript mit style verwendet werden, werden üblicherweise auch innerhalb von JavaScript definiert. Übersichtlicher ist es jedoch, alle Stile in einem Stylesheet zu deklarieren. Dort werden sie zwar ggf. gar nicht gebraucht, sie können dort jedoch einfach ausgelesen und dann innerhalb des Scripts verwendet werden. Eine perfekte Trennung zw. (semantischem) HTML, Scripting und den Layoutanweisungen ist somit leicht möglich.

Einige dieser Möglichkeiten können auch beim mehr und mehr in Mode kommenden "unobtrusive JavaScript" (USJ) von Bedeutung sein, das aus einer möglichst strikten Trennung von Script und HTML besteht. Soll eine Webseite beispielsweise mit JavaScript stilistisch verändert werden, z.B. indem man Daten versteckt, um sie erst auf Userwunsch hin wieder sichtbar zu machen, so kann das nur über statisches CSS oder dynamisches JavaScript erfolgen (die Daten selbst sollen ja - abwärtskompatibel für alle Browser wie auch für Suchmaschinen - bereits in der Webseite enthalten sein). Die CSS-Variante ist unpraktikabel, da User ohne Scripting von den versteckten Daten dann ausgeschloßen würden. Die übliche JavaScript-Variante durch Ändern der Eigenschaft oder des Klassennamens hat hingegen den Nachteil, daß dies erst dann geschehen kann, wenn das Element bereits existiert. Das bedeutet: Entweder steht der notwendige Scriptcode direkt in der Webseite (möglichst sogar direkt hinter dem jeweiligen Element - was dem Grundgedanken des UJS natürlich zuwider läuft), oder er wird, so ist es üblich, erst dann aufgerufen, wenn die Seite fertig geladen ist (gestartet durch das Onload-Event). Das bedeutet aber, daß der Besucher sehen kann, wie sich die fertig geladene Webseite vor seinen Augen gravierend ändert - ggf. obwohl er bereits mit dem Studium des Inhalts begonnen hat. Ein hoher Nutzen also für den Webautor, durch die problemlose Scriptanwendung dank UJS - eine unschöne wie irritierende "Zappelei" für den Besucher ...

Leider haben die Browser zum einen jedoch eine unterschiedliche Syntax, um auf CSS-Regeln zuzugreifen, zum anderen interpretieren sie den CSS-Code selbst ebenfalls noch unterschiedlich, so daß der intern dann tatsächlich benutzte CSS-Code sich ebenfalls noch von Browser zu Browser unterscheiden kann - sowohl was den realen Inhalt bzw. die Form einer Regel angeht, als auch ihre Position innerhalb des internen CSS-Codes (Beispiele für diese eigenwillige Interpretationen listet die Seite Change style sheet auf) - deswegen ist diese Vorgehensweise wohl auch nicht so sehr verbreitet. Mit der hier vorgestellten Funktion cssRule() kann nun sowohl eine komplette CSS-Regel als auch eine einzelne Eigenschaft einer CSS-Regel browserübergreifend ausgelesen oder geändert werden - mit Ausnahme von alten Versionen (<3) von Apples Browser Safari auch bevor die betreffenden HTML-Elemente existieren (und damit für den Surfer unsichtbar): direkt zwischen den Stildefinitionen im HEAD-Bereich und dem HTML-Body.
Generell können (momentan) allerdings keine importierten Regeln (@import) angesprochen werden! Es sind nur Stylesheets verarbeitbar, die intern mit dem STYLE-Tag (<style type="text/css">) oder als externe Datei mit dem LINK-Tag (z.B. <link rel="stylesheet" type="text/css" href="sheet.css">) eingebunden wurden - natürlich nur, sofern das Stylesheet vom der gleichen Domain eingebunden wurde (JavaScripts "Same Origin Policy" verbietet ja aus Sicherheitsgründen den Zugriff auf Daten einer fremden Domain).

Der Funktionsaufruf:

cssRule([target[,attribute[,value]]])

Der 1. Parameter target bestimmt die zu bearbeitende CSS-Regel. Mögliche Werte für target sind:

  • Ein String, der den gewünschten Selektor enthält (nicht case-sensitive, also unabhängig von Groß/Kleinschreibung). Beispiele: p für Paragraphen-Elemente (<p>), #myId für das Element mit der ID myId (<p id="myId">), .myClass für Elemente der Klasse myClass (<p class="myClass">) etc. (auch komplexere Selektoren sind möglich).
    Außerdem kann dem Selektor ein Begrenzer angehängt werden, um die Suche auf bestimmte Stylesheets zu beschränken: selector@clipper. Ist der Begrenzer eine Zahl, so wird er als Nummer des gewünschten Stylesheets interpretiert (.myClass@0 sucht den Klassen-Selektor myClass nur im 1. Stylesheet). Andernfalls wird der Begrenzer als Medientyp interpretiert, wie er im media-Attribut des Style-Tags Verwendung findet (also z.B. .myClass@print, um die Regel des Klassen-Selektors myClass anzusprechen, welches sich aber in einem Drucker-Stylesheet befinden muß: <style type="text/css" media="print">). Wird kein Begrenzer oder ein * als Medientyp übergeben (z.B. .myClass oder .myClass@*), so werden alle Stylesheets durchsucht (also z.B. <style type="text/css" media="print">, <style type="text/css" media="screen"> & <style type="text/css">). Hängt man einen "leeren" Medientyp an (z.B. .myClass@), so werden nur allgemeine, unspezifizierte Stylesheets durchsucht (<style type="text/css">).

    Es werden dann alle Regeln der gewünschten Stylesheets durchsucht, beginnend bei der letzten Regel (wenn mehrere Regeln mit gleichem Selektor existieren, überschreibt die spätere Regeln die frühere). Stimmt der Selektor einer Regel mit dem gesuchten Selektor überein, so wird die Suche beendet.

    Achtung: Gruppierte Selektoren, z.B. in p, div, pre { }, werden von den Browsern unterschiedlich verwaltet! Während z.B. Mozilla ab Version 1.75 hier (korrekterweise) auch nur eine Regel mit genau diesem Selektor hat (und eine Änderung dieser Regel sich auch auf alle drei Elemente gleichzeitig auswirkt), verwalten andere Browser (auch ältere Mozillas) intern drei gleichlautende, aber voneinander getrennte, Regeln mit dem jeweiligen Einzel-Selektor (hier also als würde man schreiben p { }, div { } & pre { })! Die Gruppierung existiert intern nicht - und kann somit auch nicht gefunden werden. Um diesem Unterschied entgegenzuwirken, kann cssRule() auch im aktuellen Mozilla (oder anderen standardkonformen Browsern) diese Regel unter jedem einzelnen der Gruppen-Selektoren finden und ansprechen.
    Sonderfall Safari: Die ersten Safaris hatten hier einen üblen Fehler. Es wurde intern weder der korrekte Gruppen-Selektor, noch alle Selektoren der Gruppe einzeln verwaltet! Stattdessen konnte man auf die Regel nur mit dem 1. Selektor der Gruppe zugreifen - im Beispiel also p. Die restlichen Selektoren div & pre waren ihnen unbekannt.

  • Ein String mit der "Adresse" (Pointer) der gewünschten Regel in der Form "Nr. des Stylesheets/Nr. der Regel", jeweils beginnend bei 0. Gültig sind also z.B. 0/0 (erstes Stylesheet/erste Regel), 1/4 (zweites Stylesheet/fünfte Regel) etc.
    Achtung: Bei komplexeren Stylesheets und komplexeren Selektoren ist, trotz gleichen CSS-Codes, die browserinterne Reihenfolge unter Umständen von Browser zu Browser unterschiedlich! Wird z.B. @import benutzt, so können bei dieser Adressierung nur Styles vor dem ersten @import browserübergreifend identisch bearbeitet werden (und selbst dann nicht immer). Diese Art der Adressierung empfiehlt sich also nur dann, wenn man entweder "einfache" Stylesheets verwendet, oder aber "weiß, was man tut". Man kann sich aber den auf dem aktuellen System gültigen Pointer mittels Schlüsselwort rulepointer als 2. Parameter (s.u.) auch von cssRule() selbst ermitteln lassen.
  • Ein Objekt, genauer: das Style-Objekt einer Regel, wie es diese Funktion auch mit der Schlüsselanweisung styleobject ermitteln kann. Wird eine Regel mehrfach angesprochen, so kann man sich auf diese Art die "Neusuche" ersparen - selbst wenn das nur bei extrem vielen & großen Stylesheets vielleicht von praktischer Relevanz sein könnte.
  • Wird kein Parameter übergeben, so wird nur getestet, ob der Browser die benötigte Funktionalität für dynamische CSS-Regeln überhaupt aufweist (der Browser Opera ist hier - mal wieder - bis zur Version 9 exkl. das Sorgenkind der JavaScript-Entwicklergemeinde).

Die eigentliche Aktion wird durch die weiteren (optionalen) Parameter bestimmt:

  • Der 2. Parameter attribute ist ein String und kann folgende Bedeutungen besitzen:
    1. Enthält der 2. Parameter eine CSS-Eigenschaft, so wird nur der in der Regel spezifizierte Wert dieser Eigenschaft verarbeitet. Dabei kann die Eigenschaft sowohl in der CSS- (font-size) als auch in der JavaScript-Syntax (fontSize) übergeben werden. Zu bevorzugen ist allerdings die CSS-Syntax, da hier alle Browser eine identische Syntax beherrschen, die JavaScript-Syntax allerdings von Browser zu Browser unterschiedlich sein kann (CSS: float / IEs JScript: styleFloat / Mozillas JavaScript bzw. ECMAScript: cssFloat). cssRule() wandelt die CSS-Syntax automatisch in die (intern benötigte) jeweils korrekte JavaScript-Syntax um.
    2. Der 2. Parameter kann auch ein Schlüsselwort enthalten, um eine spezifische Aktion zu veranlassen. Folgende Schlüsselwörter werden z.Zt. unterstützt:
      • Bei fehlendem bzw. leerem 2. Parameter oder rule wird die komplette zum übergebenen Selektor gehörende Regel verarbeitet.
      • Mit sheetobject wird das JavaScript-StyleSheet-Objekt ermittelt, dem die Regel angehört. Dieses Objekt kann zur weiteren Verarbeitung nützlich sein. Z.B. kann man so den URL auslesen, sofern es sich um ein externes Stylesheet handelt (also bei Einbindung von <link rel="stylesheet" type="text/css" media="print" href="printer.css"> und dort enthaltenem .myClass { color: red; } kann man mit cssRule(".myClass@print","sheetobject").href den URL des Stylesheets auslesen - beim Mozilla ist das der vollständige URL, beim Internet Explorer der tatsächliche Inhalt des Attributs href), jedenfalls sofern der Zugriff auf das Stylesheet erlaubt ist. Weitere sinnvolle Eigenschaften sind hier u.a. title, um auf den Titel des Stylesheets zugreifen zu können, oder disabled, um festzustellen, ob das Stylesheet aktiviert ist.

        Achtung: Bei "alternativen Stylesheets" bzw. der Eigenschaft disabled haben ältere Versionen einiger Browser, mindestens Konqueror und Safari <3, einen Bug, der eine Nutzung der "alternativen Stylesheets" unmöglich macht! Meines Erachtens ist die Nutzung alternativer Stylesheets, jedenfalls so, wie es die Browser bislang anbieten, ohnehin nur bedingt sinnvoll, da das vom Surfer ausgewählte Stylesheet jeweils nur für das aktuelle Dokument gilt. Als sinnvollere Lösung, bzw. auch als Workaround, bietet sich eher eine eigene "Stylesheet-Verwaltung" an. Dabei kann dem Surfer eine Liste mit unterschiedlichen Stylesheets angeboten werden. Der URL des gewählten Sheets kann dann z.B. in einem Cookie gesichert werden, damit die Auswahl auf der ganzen Website nutzbar ist. Der Autor muß dann nur auf jeder Seite dem LINK-Element mittels der Eigenschaft href den ausgesuchten URL zuweisen.

      • Bei sheetindex wird die Index-Nummer des gefundenen Stylesheets als Integerzahl übergeben. Wurde kein passendes Stylesheet gefunden, so wird NaN ("Not a Number") zurückgegeben anstelle des sonst üblichen false.
      • Bei rulepointer wird ein Pointer auf die gefundene Regel als String in der Form "Nr. des Stylesheets/Nr. der Regel" übergeben. Dieser Pointer kann cssRule() auch im 1. Parameter target als Zielreferenz übergeben werden. Der Pointer kann dabei, abhängig vom Quellcode, von Browser zu Browser unterschiedlich sein. D.h., ein auf einem Mozilla 1.8 ermittelter Pointer kann sich, bei identischem Quellcode, von einem auf Mozilla 1.5 ermittelten Pointer bereits unterscheiden!
        Konnte auf ein spezifiziertes Stylesheet nicht zugegriffen werden, weil dieses von einer fremden Domain eingebunden wurde ("Same Origin Policy"), so wird hier ein Leerstring zurückgegeben anstelle des sonst üblichen false.
      • Mit rulecollection erhält man die JavaScript-Collection der Regeln des gefundenen Stylesheets. Hiermit ist es z.B. möglich, direkt und browserübergreifend auf die Regeln zuzugreifen. So kann man auch mit der Eigenschaft length die Anzahl der Regeln im Stylesheet ermitteln (alert(cssRule("0/0","rulecollection").length)).
      • ruleobject übergibt das JavaScript-Objekt der gefundenen Regel. Hiermit ist es z.B. möglich, den Selektor-Text auszulesen, den der Browser intern bei dieser Regel verwendet (alert(cssRule("0/0","ruleobject").selectorText)).
      • Mit styleobject kann man das JavaScript-Style-Objekt der CSS-Regel selbst ermitteln. Mit diesem Objekt läßt sich dann in JavaScript weiterarbeiten. Es entspricht der Syntax cssRule("0/0","ruleobject").style, und kann cssRule() ebenfalls im 1. Parameter target als Zielreferenz übergeben werden.
      • Mit ownerobject kommt man browserübergreifend an das HTML-Element heran, mit dem die Styles eingebunden sind, um die entsprechenden Eigenschaft nutzen zu können. Beispiele: cssRule("0/0","ownerobject").tagName für den Namen des Style-Tags ("LINK" oder "STYLE") oder mit cssRule("0/0","ownerobject").href den URL eines externen Stylesheets, sofern vorhanden. Da hier direkt auf den eigenen HTML-Code zugegriffen wird, funktioniert dies auch dann, falls das Stylesheet als Datei eingebunden wurde, die auf einem fremden Server liegt. Außerdem kann hiermit auch der URL geschrieben werden. Man kann also das gefundene Stylesheet auch gegen ein anderes austauschen.
      • In die gleiche Kategorie gehört ownermarkup. Hier wird der (vom Browser interpretierte!) HTML-Quellcode des Style-Tags übergeben. Dies ist also entweder das STYLE-Element inkl. den Styles, oder aber das LINK-Element - jeweils inkl. ihrer Attribute. D.h., ein cssRule("0/0","ownermarkup") entspricht einem cssRule("0/0","ownerobject").outerHTML auf dem IE. Das Script bildet die Funktionalität von outerHTML einfach nach, da es sich dabei um eine proprietäre Eigenschaft des IEs handelt, die von vielen anderen Browsern überhaupt nicht oder nicht identisch unterstützt wird.

      Achtung: Die Angabe eines Schlüsselwortes kann nur dann erfolgen, wenn als 1. Parameter ein Selektor-Text oder ein Pointer (s. rulepointer), nicht jedoch, wenn das Style-Objekt einer Regel (s. styleobject) übergeben wurde! Im letzteren Fall greift cssRule() direkt auf dieses Objekt zu, ohne danach zu suchen bzw. das Stylesheet zu "kennen".

  • Wird ein 3. Parameter value übergeben, so wird die Regel bzw. Eigenschaft mit dem hier übergebenen Wert geändert.

Folgende Werte werden von der Funktion zurückgegeben:

  1. false wenn der Aufruf nicht erfolgreich war. Sei es, daß der Browser zu alt ist, sei es, daß der gesuchte Selektor nicht gefunden wurde.

    Achtung: Beim Firefox 3 ist nicht nur, wie üblich, der Zugriff auf von fremden Domains eingebundene externe Stylesheets verboten ("Same Origin Policy"). Auch wenn man die HTML-Seite, nebst CSS-Datei, von einem lokalen Laufwerk lädt, wird der Zugriff (mit einem Chrome-Fehler) verweigert - zumindest standardmäßig. Da cssRule() aber generell unerlaubte Zugriffe abfängt, wird auch in diesem Fall nur ein false als Funktionsergebnis zurückgegeben.

    Achtung: Beim Browser Konqueror wird ggf. nur ein false zurückgegeben, falls attribute leer oder rule ist, da alte Versionen einen Bug bei der zur Verarbeitung der kompletten Regel notwendigen JavaScript-Eigenschaft cssText haben.

  2. Ein JavaScript-Objekt wenn attribute ein "Objekt-Schlüsselwort" enthält. Bei
    • sheetobject das StyleSheet-Objekt, dem die Regel angehört.
    • rulecollection die JavaScript-Objekt-Collection aller Regeln des Stylesheets, dem die gefundene Regel angehört
    • ruleobject das Objekt der gefundenen Regel selbst
    • styleobject das Style-Objekt der Regel
    • ownerobject das Objekt des HTML-Elements des Stylesheets
  3. Verschiedene Datentypen, wenn attribute ein anderes Schlüsselwort enthält. Bei
    • sheetindex eine Integerzahl mit der Index-Nummer des gefundenen Stylesheets, oder NaN, falls kein passendes Stylesheet gefunden wurde
    • rulepointer ein String in der Form "Nr. des Stylesheets/Nr. der Regel" als Pointer auf die gefundene Regel, oder ein Leerstring, falls der Zugriff auf das Stylesheet nicht erlaubt ist
    • ownermarkup der (interpretierte) HTML-Quellcode des Stil-Elements
  4. Abhängig vom 3. Parameter:
    • Wenn kein value übergeben wurde:
      Komplette Regel, wenn attribute leer oder rule ist oder den Stil der Eigenschaft, die in attribute spezifiziert wurde.
    • Wenn value übergeben wurde (auch bei Leerstring):
      true, wenn die Regel oder Eigenschaft neu gesetzt werden konnte.
Beispiele für folgenden HTML-Code:
<style type="text/css"><--
 .aStil { font-size: 2em; font-weight: bold; }
--></style>
<style type="text/css" media="print"><--
 .aStil { display: none; }
--></style>
  • regel=cssRule(".aStil") um den Text der letzten aller Regeln für die Klasse aStil auszulesen - also: display: none;
  • regel=cssRule(".aStil@") um den Text der (letzten) allgemeinen (also für alle Medien geltenden) Regel für die Klasse aStil auszulesen - also: font-size: 2em; font-weight: bold;
  • groesse=cssRule(".aStil@","font-size") um die in dieser Regel definierte Fontgröße auszulesen - also: 2em
  • status=cssRule(".aStil@","","font-size: 3em; font-weight: normal";) um den Text diese Regel komplett zu ändern. Wenn status den Wert true hat, dann lautet die Regel nun .aStil { font-size: 3em; font-weight: normal; }
    Sollte status aber false sein, so gilt nach wie vor die ursprüngliche Regel - der Browser ist zu alt (oder hat einen Bug).
  • status=cssRule(".aStil@","font-size","3em") um die in dieser Regel definierte Fontgröße zu ändern. Im Erfolgsfall lautet die neue Regel nun: .aStil { font-size: 3em; font-weight: bold; }
  • cssRule(".aStil@","color","red") um die Farbe (neu) zu setzen. Im Erfolgsfall lautet die neue Regel nun also: .aStil { font-size: 2em; font-weight: bold; color: red; }
  • regel=cssRule(".aStil@print") um den Text der (letzten) druckspezifischen (also in einem Printer-Stylesheet befindlichen) Regel für die Klasse aStil auszulesen - also: display: none;
  • regelObj=cssRule(".aStil@print","ruleobject") um das diese Regel repräsentierende JavaScript-Objekt zu ermitteln. Mit diesem Objekt kann man dann weitere Änderungen durchführen - z.B.: cssRule(regelObj,"display","") um die display-Eigenschaft zu löschen. Es gilt jetzt der Default-Wert der display-Eigenschaft für die betroffenen Elemente (d.h., das Element würde im Ausdruck erscheinen - die Regel wäre jetzt leer).
  • if(!cssRule("body@print","font-size","12pt")) { addStyle("body { font-size: 12pt; }","print"); } versucht in einem Drucker-Stylesheet die Textgröße des Elements BODY auf 12pt zu ändern, und erstellt mittels addStyle() 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:
setCssStyle() (Kombination cssRule() & addStyle())

Testseite 1: cssRule()-Beispiele
Testseite 2: setCssStyle()-Beispiele
(cssRule() & addStyle() kombiniert)
Testseite 3: Vergleichstest
(cssRule() & toggle() - basierend auf Lion IBrowse)

Der externe Quellcode: cssrule.zip

The function cssRule() offers a cross-browser compatible way to read and change styles within style sheets (STYLE or LINK elements) (for adding new style sheets or rules use addStyle()). Although different browser incompatibilities do exist, it should be possible to access wanted CSS rules and/or their styles within just by searching the sheets with a given selector - even at definable media types (i.e. just to change the style of an element for printer and not for screen output). In addition: It is the only way to read & change pseudo formats (i.e. :hover). The function call:

cssRule([target[,attribute[,value]]])

The 1st parameter target determines the wanted CSS rule. Possible values are:

  • A string containing the wanted selector (case insensitive), i.e. p for paragraph elements (<p>), #myId for the element with ID myId (<p id="myId">), .myClass for elements of the class myClass (<p class="myClass">) etc.
    In addition you can add a clipper to the selector to specify the style sheets searched: selector@clipper. If the clipper is a digit, it will be interpreted as the number of the wanted style sheet (i.e. .myClass@0 for searching the class selector myClass just in the 1st style sheet). Otherwise the clipper will be interpreted as a media type, like it is been used at the media attribute of the STYLE tag (i.e. .myClass@print for accessing the rule of the class myClass which has to be in a printer style sheet: <style type="text/css" media="print">). With no media type or an * as media type given (i.e. .myClass or .myClass@*), all style sheets will be searched (i.e. <style type="text/css" media="print">, <style type="text/css" media="screen"> & <style type="text/css">). Adding an "empty" media type (i.e. .myClass@) will take care that only unspecified style sheets will be searched (<style type="text/css">).

    The search is starting at the last rule of the last style sheet, going upwards, ending with the first match.

    Attention: Group selectors, i.e. p, div, pre { }, are also treated differently by the browsers (1 correct selector at Mozilla since version 1.75, 3 separated ones at IE and 1 shortened to p at Safari <3). So cssRule() can find the rule by giving each selector of the group separately (of course: just the 1st at older Safaris =;-))!

  • A string with a pointer to the wanted rule "no. of style sheet/no. of rule" starting with 0 (i.e. 0/0 for 1st style sheet/1st rule, 1/4 for 2nd style sheet/5th rule, etc.)
    Attention: Avoid pre-defined pointers because of different browser behaviour! Let cssRule() find out the pointer instead by using the key word rulepointer as 2nd parameter (see below).
  • An object (more precisely: style object) which can be acquired with the key word styleobject.
  • If no parameter is given, cssRule() will just test the browser for the necessary functionality.

The real action is caused by the following (optional) parameters:

  • The 2nd parameter attribute is a string with the following meanings:
    1. Give a CSS property and just the in the rule specified value of this property will be handled. The allowed syntax is of CSS (font-size) or JavaScript (fontSize) type (prefering CSS type because of, you might guess it, browser incompatibilities - CSS: float / IEs JScript: styleFloat / Mozillas JavaScript: cssFloat).
    2. The 2nd parameter can contain a key word. At the moment these key words are:
      • rule (or an empty string or even no 2nd parameter at all) for accessing the complete rule, exactly: the whole set of styles of the rule according to the given selector.
      • sheetobject for retrieving JavaScript's styleSheet object of the rule found.
      • sheetindex for retrieving style sheet's index number as an integer. If no appropriate style sheet was found, NaN ("Not a Number") will be returned instead of the usual false.
      • rulepointer for a (string) pointer of style sheet/rule - as accepted as 1st parameter target. If access is prohibited, an empty string will be returned instead of the usual false.
      • rulecollection for the entire collection of rules of the style sheet found. With it you can cross-browser access this collection, regardless whether the browser is using rules (IE) or cssRules (other browsers). I.e. you can get the number of rules by using length (alert(cssRule("0/0","rulecollection").length)).
      • ruleobject for the JavaScript object of the rule itself, i.e. to get the (internal) selector text used by the browser (alert(cssRule("0/0","ruleobject").selectorText)).
      • styleobject for the JavaScript style object of the rule. It accords to the syntax cssRule("0/0","ruleobject").style, and can also be used as 1st parameter target.
      • ownerobject for the HTML object of the style sheet. I.e.: use cssRule("0/0","ownerobject").tagName to get the type of the style tag ("LINK" or "STYLE").
      • ownermarkup for the HTML markup of the style tag (which also may be the browser's interpreted one).
      Attention: Use a key word only if a selector or a pointer (see rulepointer) is used as 1st parameter, not if a rule's style object (see styleobject) was given! In the latter case, cssRule() has direct access without searching or "knowing" the style sheet.
  • Giving a 3rd parameter value changes the CSS text of the rule, respectively the wanted property of the rule, to the given value. Examples: To set the font size in the last occuring class selector "text" (regardless of the media type) to "2em", write cssRule(".text","font-size","2em"), to replace the CSS text of the latest rule with ID selector "head" at a printer style sheet write cssRule("#head@print","rule","font-size: 2em; font-weight: bold;") and to erase all the styles (not the rule itself) of that ID selector in a style sheet for screen, write cssRule("#head@screen","rule","") or shorter cssRule("#head@screen","","") - every time returning true on success and false on failure.
Test page 1: cssRule() examples
Test page 2: Comparing test of cssRule() with toggle()

The external source code: cssrule.zip



Updates:
29.09.2007: 
Korrekturen: Beim letzten Update hatte sich ein Fehler eingeschlichen: W3C-DOM-Browser fanden/änderten auch Stile, wenn der Selektor, nicht aber der angegebene Medientyp paßte. Außerdem eine generelle Änderung: W3C-Browser haben (im Gegensatz zum IE) bei der Ermittlung des HTML-Quelltextes (Schlüsselwort: ownermarkup) von STYLE-Elementen mit dem verwendeten innerHTML bzw. outerHTML dynamische Änderungen nicht wiedergegeben. cssRule() ermittelt jetzt den tatsächlichen Quelltext komplett selbst.
04.08.2007: 
Korrektur: Safari-2.x-Workaround eingebaut wg. Scriptabbruch wenn mediaText===null mit anschl. String-Methode (hier: mediaText.toLowerCase()).
05.07.2006: 
Korrektur: Die Anpassung für IE/Mac (er kennt nicht nur das MS-typische rules-Objekt, sondern auch das offizielle cssRules-Objekt, jedoch ohne dessen Funktionalität) kollidierte mit dem Konqueror (bei dem es genau umgekehrt ist =:-)), was eine erneute Anpassung notwendig machte. Außerdem werden jetzt nicht nur im Selektor-Text einzeln auftretende "verhunzte" CLASS & ID-Selektoren korrigiert, sondern auch mehrfach auftretende.
01.07.2006: 
Korrekturen & Erweiterung: Der Safari-Workaround funktionierte nicht mit Selektoren mit "-", und eine Anpassung für IE/Mac war notwendig. Neu hinzugekommen ist die Möglichkeit, Selektoren nur in einem speziellen Stylesheet suchen zu lassen (p@0 als target-Parameter für eine Suche nur im 1. Stylesheet).
28.06.2006: 
Korrektur & Erweiterung: Hurra - 1. Workaround für Opera-Browser! Die Version 9 hat die notwendige Funktionalität jetzt ebenfalls. Da arbeitet man doch gerne um einen kleinen Browser-Bug (er meldet beim Zugriff auf ein nicht vorhandenes Stylesheet ggf. ein object statt undefined) herum ... ;-)
Außerdem wurde ein Bug in der Attribut-Selektor-Entfernung des Safari-Workarounds behoben und die Routine verfeinert: es werden nur noch exakt die Attribut-Selektoren entfernt, die überflüssig sind.
Interne Änderung: Das Umwandeln der Style-Schreibweise von CSS- auf JS-Syntax wurde in eine separate Funktion ausgelagert.
22.06.2006: 
Erweiterung: Neue Schlüsselwörter hinzugefügt (sheetindex, rulepointer, rulecollection, ruleobject, ownerobject und ownermarkup).
17.06.2006: 
Korrekturen: Fehler bei Verwendung von Gruppen-Selektoren in Mozilla >= 1.75 behoben (war der Selektor einer Regel nochmals in einer Gruppe aufgeührt, dann wurde die Suche nicht beim Gruppen-Selektor abgebrochen). Außerdem werden jetzt automatisch eventuell vorhandene Attribut-Selektoren [CLASS~="..."] & [ID"..."] aus dem Selektor-Text entfernt (sie werden beim Safari eigenmächtig hinzufügt, und verhinderten die erfolgreiche Suche nach Klassen- & ID-Selektoren in "normaler" Schreibweise).
26.05.2006: 
Erweiterung: Stylesheets können nach Medientyp unterschieden werden, Stylesheet-Objekt ist ermittelbar und Fehler beim illegalen Zugriff auf externe Stylesheets von fremden Servern werden abgefangen.


Kurz-URL dieses Artikels: http://Coding.binon.net/CSS-Rules