Java(-Script) Workshops -> Fließender Hover-Effekt, Browserunabhängig

Fließender Hovereffekt in JS, Browserunabhängig

Ich habe schon mehrere Male in Foren gelesen dass User Scripts brauchten, um einen Übergang von einer Farbe zur anderen zu erreichen - quasi einen "edlen" Hover-Effekt. Natürlich bietet der Internet Explorer für diese Wünsche vielfältige dynamische Filter (dazu siehe SelfHTML ), aber das ist natürlich wieder alles andere als gut, nur für den MS-Riesen zu designen...
Deshalb habe ich mich entschieden, in diesem Workshop ein browserunabhängiges Script vorzustellen, das konfigurierbar ist was die Farben und die Dauer des Effektes angeht und beliebig viele "Hover"-Schaltflächen verwalten kann.
Der Farbwechsel bezieht sich dabei bei meinem Script immer auf die Vordergrundfarbe, man kann ohne Probleme auch die Hintergrundfarbe ändern lassen indem man nur eine Zeile austauscht, dazu mehr am Ende des WS.
Sinnvollerweise sollte der Leser dieses WS Vorkenntnisse über JavaScript mitbringen, und z.B. bescheid wissen, was onMouseOver etc. bedeutet.
Doch genug der Vorrede, es geht an die Umsetzung!

Die theoretischen Vorüberlegungen

Zunächst einmal: Was für Variablen braucht mein Script später? Wie wird es aufgerufen? Wie kann man es konfigurierbar gestalten?

Das mit dem Aufruf ist leicht zu klären, das ist standard und sollte jedem JavaScript-Coder nicht komisch vorkommen: So würde eine Hoverschaltfläche aussehen, die mit dem Effekt verschönert wird:

<a href="blablabla.html" id="button01" onMouseOver="fade_m('button01')" onMouseOut="fade_um('button01')" style="color:#000000">TEXTTEXTTEXT</a>

Wie man sieht, erhält der Button eine ID (button01), und diese wird dazu genutzt, um die Funktionen aufzurufen (Dazu noch ein kleiner Hinweis: immer wenn eine Funktion oder Variable mit m gekennzeichnet ist, bedeutet das in diesem Script markiert bzw. markieren (also Hovereffekt) und alles mit um bedeutet unmarkiert bzw. markierung entfernen).

Was für Variablen brauchen wir aber?

Für jeden Button, der verwaltet wird, brauchen wir eine Variable, die Speichert, an welchem Punkt des Hovereffektes sich dieser Button gerade befindet. Nun hatte ich aber versprochen, dass mein Script beliebig viele Buttons unterstützt - also ist natürlich eine Variable pro Button zu deklarieren Quatsch, sondern wir verwenden ein assoziatives Array (dazu siehe SelfHTML ) ohne eine Größe festzulegen:

var Step=new Array();

Genauso speichern wir für jeden Button die Richtung des Effektes, also ob dieser gerade ein- oder ausfadet:

var Dir=new Array();

Zum dritten Punkt: Wie kann man das Script konfigurierbar gestalten?
Verändern können sich eigentlich nur die Farben (markiert und unmarkiert) und die Geschwindigkeit des Effektes.
Die Farben werden dazu einmal global im Script in ihren Rot/Grün/Blauanteilen deklariert:

Farben ohne Effekt:

var Rum=0;
var Gum=0;
var Bum=0;


dies würde in HTML #000000 entsprechen - also schwarz. (Man beachte: um für unmarkiert)

Farben mit Effekt:

var Rm=255;
var Gm=128;
var Bm=128;


in diesem Falle rosa, was #ff8080 in HTML wäre. (Dabei wieder m für markiert)

Die Geschwindigkeit habe ich von 2 Faktoren abhängig gemacht: Die Anzahl der Schritte (Steps) und die Verzögerung zwischen den Schritten (Delay) Je mehr Schritte, desto weicher ist der Übergang und je höher das Delay, desto länger braucht die Animation. Für mehr Schritte wird natürlich auch mehr Rechenleistung benötigt. Ein guter Ausgangswert ist z.B.:

var Steps=16;
var Delay=30;

-> 16 Schritte mit einer Verzögerung von 30 Millisekunden pro Schritt.

Der Variablendeklarationsteil und der Aufruf ist damit fertig. Jetzt fehlt nur noch die eigentliche Arbeit: Der Code an sich.

Der Funktionscode

Der Code besteht aus 3 Funktionen: Eine initiiert das Einfaden, eine das Ausfaden und eine ist die Zentrale Fade-funktion. Die beiden erstgenannten sind dabei sehr ähnlich. Betrachten wir zunächst die erste:

function fade_m(t) {
if (isNaN(Step[t])) Step[t]=0;
Dir[t]=1;
change(t);
return;
}


t steht dabei jeweils für das Zielobjekt, also die ID des Links. In der ersten Zeile wird zunächst überprüft, ob Step[t] bereits mit einer Zahl belegt ist (isNaN bedeutet "is not a number" - wenn der Button noch nicht benutzt wurde, enthält Step[t] noch den Wert undefined), wenn nicht, dann bedeutet das, dass der Button zum ersten Mal dem Script übergeben wurde und es wird der Wert 0 gespeichert (0 bedeutet also: Anfang des Effektes, völlig unmarkiert). Die Richtung (Dir[t]) wird dann auf 1 gesetzt, das bedeutet: der Button soll langsam markiert werden. Dann wird noch mit change(t) die eigentliche Effektfunktion aufgerufen.
Wie bereits angekündigt, sieht die zweite Funktion fast genau so aus wie die erste:

function fade_um(t) {
if (isNaN(Step[t])) Step[t]=Steps;
Dir[t]=-1;
change(t);
return;
}


Das einzige, was sich geändert hat, ist die Zuweisung von Step[t] und Dir[t]. Step[t] wird jetzt auf Step gesetzt, das bedeutet: Vollkommen markiert. Dir[t] wird auf -1 gesetzt, das bedeutet: der Button soll seine Markierung langsam verlieren.

Das Herzstück: die function change(t)

Jetzt wird es spannend, denn in dieser Funktion passiert die eigentliche Arbeit. Hier zunächst der Code:


function change(t) {
R=Rum + parseInt((Step[t]* (Rm-Rum))/Steps);
G=Gum + parseInt((Step[t]* (Gm-Gum))/Steps);
B=Bum + parseInt((Step[t]* (Bm-Bum))/Steps);
RGB="#";
if(R<16)RGB+="0";
RGB+=R.toString(16);
if(G<16)RGB+="0";
RGB+=G.toString(16);
if(B<16)RGB+="0";
RGB+=B.toString(16);
document.getElementById(t).style.color=RGB;
if((Step[t]==Steps) && (Dir[t]==1)) return;
if((Step[t]==0) && (Dir[t]==-1)) return;
Step[t]+=Dir[t];
window.setTimeout("change('"+t+"')",Delay);
}


Und die Erläuterung folgt auf dem Fuße. In den ersten 3 Teilen werden aus der Information über den Fortschritt des Effektes (gespeichert in Step[t]), den Werten für die Ausgangs- und die Zielfarbe und der Anzahl der Schritte die 3 Farbanteile für die aktuelle Farbe gebildet.
Langsam auseinandergenommen:

R -> Zielwert für Rot
=
Rum -> Ausgangswert für völlig unmarkiert
+
parseInt( -> Mit Kommazahlen können wir nichts anfangen
(Step[t]* -> So weit ist der Effekt schon
(Rm-Rum)) -> Die insgesamt zu überwindende "Distanz"
/Steps); -> Das ganze nur für einen Teilschritt

Bei den anderen beiden Farbanteilen Grün und Blau funktioniert das dann genauso.
Die folgenden Zeilen

RGB="#";
if(R<16)RGB+="0";
RGB+=R.toString(16);
if(G<16)RGB+="0";
RGB+=G.toString(16);
if(B<16)RGB+="0";
RGB+=B.toString(16);


erstellen aus den dezimalen Werten für Rot, Grün und Blau den HTML-Typischen Hex-Code für Farben. Die Methode toString(basis) wandelt dabei die Dezimalzahlen in Zahlen mit der Basis 16 (also Hexadezimal) um. Wenn die Zahl kleiner ist als 16 muss dabei jeweils noch eine 0 eingefügt werden. Die Raute # in der Ersten Zeile ist ja von HTML-Farbangaben bekannt.
In der nächsten Zeile document.getElementById(t).style.color=RGB; wird dann zunächst mit der Methode document.getElementById(t) ein HTML-Elementobjekt für den Button mit der übergebenen ID erstellt, welches dann manipuliert werden kann - in diesem Falle über die Eigenschaft color seines Unterobjektes style. Dieser Eigenschaft wird nämlich der soeben erstellte Hex-Code für die aktuelle Farbe zugewiesen.

if((Step[t]==Steps) && (Dir[t]==1)) return;
if((Step[t]==0) && (Dir[t]==-1)) return;


Diese beiden Zeilen haben eine ganz einfache Aufgabe: Sie überprüfen, ob der Effekt fertig ausgeführt wurde. Wenn das der Fall ist (entweder: Ganz markiert, Richtungsvariable steht auf markieren, oder: ganz unmarkiert, Richtungsvariable steht auf markierung entfernen), so wird die Funktion durch return beendet. Andernfalls geht es so weiter: Step[t]+=Dir[t];. Hier wird einfach der Fortschrittszähler in die angegebene Richtung weitergestellt. Am Ende wird noch ein Timeout gesetzt: window.setTimeout("change('"+t+"')",Delay); Das bedeutet, dass nach der Zeit von Delay Millisekunden wiederum die funktion change(t) aufgerufen wird, um den nächsten Schritt des Effektes zu machen.
Damit ist das Script erklärt, hier noch einmal der ganze Code zum Kopieren:


<!--Fading Hover Effect v1.0 (c)2003 by Triple-M-->
<script type="text/javascript">
<!--
var Steps=16;
var Delay=30;

var Rum=0;
var Gum=0;
var Bum=0;

var Rm=255;
var Gm=128;
var Bm=128;

var Step=new Array();
var Dir=new Array();

function change(t) {
R=Rum + parseInt((Step[t]* (Rm-Rum))/Steps);
G=Gum + parseInt((Step[t]* (Gm-Gum))/Steps);
B=Bum + parseInt((Step[t]* (Bm-Bum))/Steps);
RGB="#";
if(R<16)RGB+="0";
RGB+=R.toString(16);
if(G<16)RGB+="0";
RGB+=G.toString(16);
if(B<16)RGB+="0";
RGB+=B.toString(16);
document.getElementById(t).style.color=RGB;
if((Step[t]==Steps) && (Dir[t]==1)) return;
if((Step[t]==0) && (Dir[t]==-1)) return;
Step[t]+=Dir[t];
window.setTimeout("change('"+t+"')",Delay);
}

function fade_m(t) {
if (isNaN(Step[t])) Step[t]=0;
Dir[t]=1;
change(t);
return;
}

function fade_um(t) {
if (isNaN(Step[t])) Step[t]=Steps;
Dir[t]=-1;
change(t);
return;
}
//-->
</script>


Aufgerufen wird das ganze wie weiter oben beschrieben. Ein Bespiel findet ihr hier.

Wie versprochen, noch die Änderung wenn man den Hintergrund statt der Schriftfarbe verändern will:
in der function change(t) muss nur die Zeile
document.getElementById(t).style.color=RGB;
so verändert werden:
document.getElementById(t).style.backgroundColor=RGB;

Ich hoffe, ihr konntet was lernen und/oder dieses Script nutzbringend einsetzen. Ich habe es getestet unter dem IE5, IE6, Opera 7.10 und Mozilla 1.2.1 - Da funktioniert es einwandfrei.

Hinweis: Wenn man mehrere Links mit dem Effekt versehen will, muss man jedem Link eine neue ID geben:

<a href="blablabla.html" id="button01" onMouseOver="fade_m('button01')" onMouseOut="fade_um('button01')" style="color:#000000">TEXTTEXTTEXT</a>
<a href="blablabla.html" id="button02" onMouseOver="fade_m('button02')" onMouseOut="fade_um('button02')" style="color:#000000">TEXTTEXTTEXT</a>