Glow — Manipulation am Stylesheet
Experimente mit Javascript und dem Stylesheet-DOM
Während der letzten autodidaktischen Fortbildung habe ich mich mit dem Document Object Module der Stylesheets befasst. Kann ich die Farbe einer CSS-Klasse dynamisch ändern? Gleich wie beim HTML-DOM können in Theorie CSS-Regeln als Knoten ausgelesen, gelöscht, umgeschrieben oder hinzugefügt werden. Leider scheint die Implementierung uneinheitlich, das Finden eines bestimmten Knotens eine aufwändige Objektbaum-Traverse, wobei die Details von Browser zu Browser variieren. Mit einem Trick lässt sich die Suche aber umgehen: Es reicht, eine neue Regel mit der gewünschten Definition ans Ende der bestehenden Regeln anzuhängen, da in CSS spätere Regeln frühere überschreiben. Weil der Index der hinzugefügten Regel bekannt ist, kann später leicht auf den Knoten zugegriffen werden.
Das Skript glow.js
Hier nun das Glow-Skript in Aktion. Die Farbe aller HTML-Elemente, die mit der CSS-Klasse class="glow" ausgezeichnet sind (zum Beispiel dieser Absatz), pulsiert kontinuierlich zwischen zwei festgelegten Farbwerten.
Je nach verwendetem CSS-Selektor können andere Seitenelemente angesprochen werden
- Variante 1 mit Selektor .class
- Variante 2 mit den Selektoren h1, h2, h3
- Variante 3 für alle Links
- Variante 4 noch eins draufgesetzt
Bemerkungen zum Skript
- rgb1 und rgb2 enthalten die beiden Endfarben der Skala.
- In styleSelector wird der CSS-Selektor festgelegt. Je nach vorhandenem Stylesheet sind Zusatzangaben nötig. Auf endo.ch sind zum Beispiel einige Farbangaben mit dem prioritären ID-Selektor #maincontent definiert, deshalb muss diese Angabe hier wiederholt werden, sonst passiert nichts. Als Faustregel gilt: Wenn der Selektor von Hand als letzte Regel im Stylesheet eingesetzt funktioniert, funktioniert auch das Skript.
- step steuert die Pulsgeschwindigkeit (kleine Schritte = langsam, grosse Schritte = schnell).
- Die Hilfsfunktion addListener() stell sicher, dass das Skript erst startet, nach dem die Seite komplett fertig geladen ist.
- In der Funktion startglow() wird die neue Regel an den CSS-Objektbaum angehängt, danach wird die Variable styleSelector zum Speichern des neuen Objektknotens missbraucht.
- Die Funktion glow() ist die eigentliche "Endlosschleife" für den Farbwechsel.
Quelltext des aktuell verwendeten Skripts:
// Simple JavaScript Glow Effect // (c) endo.ch 2008, Christoph Berger, www.endo.ch var rgb1 = [102, 102, 102]; var rgb2 = [000, 163, 187]; var styleSelector = '.glow, #maincontent .glow'; var step = 16; addListener(window, 'load', startglow); function glow(count) { // count: 0 bis 50 (zunehmend) 50 bis 100 (abnehmend) var prog = (count > 50) ? 100-count : count; var rgbNew =[ Math.floor(rgb1[0]+prog*(rgb2[0]-rgb1[0])/50), Math.floor(rgb1[1]+prog*(rgb2[1]-rgb1[1])/50), Math.floor(rgb1[2]+prog*(rgb2[2]-rgb1[2])/50) ]; var color = 'rgb('+rgbNew[0]+','+rgbNew[1]+','+rgbNew[2]+')'; for(s=0; s<styleSelector.numOfRules; s++){ styleSelector.ruleSet[styleSelector.ruleIndex+s].style.color = color; } window.setTimeout('glow('+((count+step)%100)+')', 150); } function startglow() { var property = 'color: rgb('+rgb1[0]+','+rgb1[1]+','+rgb1[2]+')'; var i = document.styleSheets.length-1; var ruleSet = (document.styleSheets[i].cssRules) ? document.styleSheets[i].cssRules : document.styleSheets[i].rules; var index = ruleSet.length; var selectors = new Array(); var numOfRules = 0; if (document.styleSheets[i].addRule){ // IE braucht für jeden Selektor eine eigene Regel selectors = styleSelector.split(','); numOfRules = selectors.length; for(s=0; s<numOfRules; s++){ document.styleSheets[i].addRule( selectors[s], property, index+s ); } } else{ numOfRules = 1; document.styleSheets[i].insertRule( styleSelector+' {'+property+'}', index ); } // Safari Bug?? ruleSet neu zuweisen ruleSet = (document.styleSheets[i].cssRules) ? document.styleSheets[i].cssRules : document.styleSheets[i].rules; styleSelector = {'ruleSet': ruleSet, 'ruleIndex': index, 'numOfRules':numOfRules }; // globale Variable glow(0); } function addListener(element, event, listener, bubble) { if(element.addEventListener) { if(typeof(bubble) == "undefined") bubble = false; element.addEventListener(event, listener, bubble); } else if(document.attachEvent) { element.attachEvent("on" + event, listener); } }
Fazit
Das Experiment ist zweifelsfrei geglückt. Es stellt sich dennoch die Frage: Wozu kann ich die Erkenntnisse verwenden? Erst gerade wurde das Verschwinden des blink-Tags gefeiert, und nun dies! Manchmal bin ich entsetzt ab mir selber.