Tutorial: OS X Dock

OS X Dock Bild 1 OS X Dock Bild 2 OS X Dock Bild 3
HTML5 CSS3 jQuery

Testumgebung

Betriebssystem: Mac OS X 10.8.5
Desktop-Browser: Safari 6.1, Chrome 31.0.1650.57, Firefox 25.0.1

Anmerkungen

Dieses Tutorial wurde zu reinen Demonstrationszwecken geschrieben. Eine Optimierung für mobile Endgeräte wurde nicht vorgenommen. Da dies mein erstes Tutorial ist, werde ich auf alles etwas genauer eingehen. Nachfolgende Tutorials werden deshalb einen Verweis auf mein erstes bekommen, um bei Unklarheiten noch einmal genauer nachlesen zu können. Ich mache dies, um sich wiederholende Abschnitte nicht erneut erläutern zu müssen und weil ich in meinen damaligen Anfangstagen viel nach Tutorials gesucht habe, die mir zwar das Ergebnis lieferten, aber die ich dennoch nicht wirklich verstand.
Sollte JavaScript deaktiviert sein, kann das Dock in dieser Version nicht genutzt werden. Abhilfe schafft hierbei ein selbstständiges Kopieren und Einfügen der aufgeführten Liste zur Spiegelung. So muss das Klonen nicht über JavaScript geschehen. Fügt man den Icons nun noch ein title hinzu, so wird am Mauszeiger dessen Name angezeigt. Die zwei Zeilen bzgl. des Klonens in der JavaScript-Datei können dann gelöscht werden. Dieser Tipp ist jetzt noch etwas verwirrend, aber nach Lesen des Tutorials sollte klar werden, was ich damit meine.

HTML (HyperText Markup Language)

Eine gewöhnliche HTML-Datei besteht grundsätzlich aus folgenden Teilen. Als erstes steht die Dokumenttyp-Deklaration. Sie definiert die verwendete HTML-Version. Seit HTML5 hat sich diese deutlich verkürzt und trägt somit zur Übersichtlichkeit bei.
Danach folgt des HTML-Wurzelelement <html>, worin sich der Kopfbereich <head> befindet, mit verschiedenen Angaben zum Zeichensatz, Angaben für Suchmaschinen, Verweise zu externen Stylesheets oder JavaScript-Dateien, internen Style-Angaben <style> oder aber den Titel des Dokuments <title>, welcher im Kopf des Browsers beim Aufrufen der Internetseite erscheint. Auf die Style-Angabe im Kopfbereich gehe ich später näher ein. Es gibt aber noch unzählige weitere Möglichkeiten für solche Angaben.
Nachdem der Kopfbereich wieder geschlossen wurde (jedes geöffnete HTML-Element muss wieder geschlossen werden), folgt der Körper des Dokuments <body>, in den der gesamte anzuzeigende Inhalt, wie Texte mit Überschriften, Verweise, Tabellen, Grafikreferenzen und vieles mehr, geschrieben wird.

1
2
3
4
5
6
7
8
9
10
11
12
13
33
34
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="robots" content="noindex, nofollow">
<link rel="stylesheet" type="text/css" href="css/style.css">
<title>HTML5, CSS3, jQuery – OS X Dock</title>
<style type="text/css">
nav > div:last-child > ul > li img { filter:url(#blur-effect) }
</style>
</head>
<body>
<!-- Bereich der darzustellenden Daten -->
</body>
</html>

Der <body>

Um die Semantik weiter zu fördern, wurden in HTML5 neue Elemente hinzugefügt (sowohl struktur- als auch textsemantisch). Das Element <section> dient hier lediglich zum Zentrieren des Menüs <nav> sowie zum Fixieren am Boden des Bildschirms. Die Unterteilung der einzelnen Links erfolgt über eine ungeordnete Liste <ul> und dessen Listenelementen <li>. Eingebettet in die Listenelemente, liegen Verweise zu weiterführenden Internetseiten oder Ankern innerhalb des Dokuments. Diese umschließen wiederum Referenzen zu Bilddateien. Sollte eine Bilddatei nicht geladen werden können, wird der alternative Text alt="" angezeigt.

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!-- Firefox svg blurring -->
<svg id="svg-image-blur">
<filter id="blur-effect">
<feGaussianBlur stdDeviation="2">
</filter>
</svg>
<section id="icon-dock">
<nav>
<div>
<ul>
<li><a href=""><img src="img/icon-1.png" alt="Finder"></a></li>
<li><a href=""><img src="img/icon-2.png" alt="Launchpad"></a></li>
<li><a href=""><img src="img/icon-3.png" alt="Utilities"></a></li>
... <!-- weitere Elemente in der Liste -->
</ul>
</div>
</nav>
</section>
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="js/animation.js"></script>

Die Bedeutung des Abschnitts bzgl. der Vektorgrafik <svg> greife ich zu einem späteren Zeitpunkt erneut auf.
Um ein schnelleres Laden des Dokuments zu erzielen und zuerst das Markup sowie die Stylesheet-Angaben abzuarbeiten, wird der JavaScript-Teil <script> bevorzugt am Ende des Dokuments gelistet.
Das erste externe Script ist die JavaScript-Bibliothek jQuery, welche auf einer Vielzahl von Browsern läuft. Sie bietet Unmengen an Methoden zum DOM-Traversal (Document Object Model = plattform- und sprachunabhängige Schnittstelle für dynamischen Zugang zu Inhalt, Struktur und Aussehen von HTML-Dokumenten) und zur Manipulation, zur Ereignisverarbeitung, Animation und für AJAX (Asynchronous JavaScript And XML = asynchrone Datenübertragung zwischen Browser und Webserver, sodass neue Inhalte ohne komplettes Laden eines HTML-Dokuments eingebunden werden können).
Das zweite Script dient der Implementation des eigenen Quelltexts für die Animationen.

CSS (Cascading StyleSheets)

Stylesheets bilden eine Erweiterung der HTML-Elemente. Zuerst durch Firmen wie Netscape und Microsoft erweitert, stieg die Inkompatibilität schnell an, sodass 1994 ein Standard durch das W3C eingeführt wurde. Die aktuellste Version der CSS ist modular aufgebaut. Es gibt Unterteilungen in 2D- und 3D-Transformationen, Animationen, Transitionen, Hintergründe, Texteffekte u.a. Eine höhere Version als Version 3 soll es nicht mehr geben, da nun die einzelnen Module separat aktualisiert werden können.
Im Folgenden wird das Stylesheet des "OS X Dock" nach und nach erklärt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
html, body
{
width: 100%;
height: 100%;
margin: 0;
padding: 0;
background: url(../img/mountainLion.jpg) no-repeat center center;
background-size: cover;
font-family: Arial, Helvetica, sans-serif;
font-size: 16px;
font-style: normal;
}

svg
position: absolute;
opacity: 0.0;
}

Unter dem Punkt html, body werden zuerst einmal grundlegende Einstellungen des Dokuments vorgenommen, wie z.B. Festlegung der Höhe und Breite. Der Hintergrund erhält ein Bild, welches sich nicht wiederholt und horizontal sowie vertikal zentriert wird. Die Einstellung background-size passt das Bild dann im Verhältnis optimal jeder möglichen Browserauflösung an. Zusätzlich werden verschiedene Einstellungen bzgl. der Schrift vorgenommen, welche an Kindelemente veerbt werden.
Die Eigenschaften für svg sollen lediglich den Container verdecken und unabhängig von anderen Elementen im Dokument positionieren.

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#icon-dock {
position: fixed;
width: 100%;
bottom: 0;
text-align: center;
}

nav {
position: relative;
display: inline-block;
height: 28px;
border-bottom: 32px solid rgba(255, 255, 255, 0.6);
border-left: 27px solid transparent;
border-right: 27px solid transparent;
box-shadow: 0px 5px rgba(255, 255, 255, 0.8);
}

Wie schon zuvor erwähnt wird das Element mit der ID #icon-dock auf die volle Breite eingestellt und am unteren Rand des Bildschirms über position und bottom fixiert, sodass es beim Scrollen immer mitgehen würde. Die Einstellung text-align (horizontale Ausrichtung) richtet inline-Elemente in block-Elementen aus. Block-Elemente selbst werden über margin ausgerichtet, wobei gleiche Werte für margin-left und margin-right eine Zentrierung bewirken können.
HTML-Elemente dürfen, wie zu sehen, ineinander verschachtelt werden. In einem body-Element liegen p-Elemente, in einem p-Element können a-Elemente liegen. Nicht jedes HTML-Element darf in jedem HTML-Element stehen. Öffnende und schließende Tags dürfen sich nicht überkreuzen. Wichtig für die Strukturierung und das Layout von Internetseiten ist eine saubere Verschachtelung.
Block-Elemente belegen ohne Formatierung durch CSS immer die gesamte Breite des Elternelements; die Höhe des Blocks wird durch seine Inhalte bestimmt und ein neuer Block beginnt immer in einer neuen Zeile. Inline-Elemente hingegen nehmen nur den Platz ein, den ihr Inhalt braucht und starten nicht in einer neuen Zeile. Außerdem dürfen sie keine block-Elemente enthalten.
Das Element nav ist, von seinem Verhalten her ohne Formatierung, ein block-Element, welches die gesamte Breite des Elternelements einnimmt und nicht zentriert ist. Die Änderung des Verhaltens erfolgt über display: inline-block. Das Element wird somit selbst zu einem inline-Element; der Inhalt wird als block-Element dargestellt.
Die Angaben für die Rahmen bestimmen das Aussehen des Regals. Wahlweise kann der Rahmen für alle Seiten angegeben werden oder aber, wie hier, einzeln für jede Seite. Der erste Wert steht für die Breite des Rahmens, der zweite für den Stil und der letzte für die Farbe. Die Rahmen links und rechts können durch die Farbangabe transparent zu einer Schrägen umgestaltet werden. Die Höhe des Regals wird durch die Höhe der enthaltenen Elemente, also die einzelnen Icons, bestimmt. Diese liegen normalerweise auf dem unteren Rahmen. Durch die Angabe einer Höhe, kleiner als die Höhe der Icons, rutschen diese auf den Rahmen nach unten. Um den 3D-Look des Regals noch weiter zu verstärken erhält das Element zusätzlich einen Schatten, mit einer vertikalen Angabe von 5 Pixeln und einer scharfen Kante (Wert für weiche Kante weggelassen).

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
nav > div:first-child > p {
position: absolute;
top: -120px;
padding: 3px 10px;
background: rgba(0, 0, 0, 0.5);
color: #FFF;
text-shadow: 0px 1px #000;
border-radius: 15px;
font-weight: bold;
display: none;
}

nav > div:first-child > p:after {
position: absolute;
content: "";
top: 24px;
left: 50%;
margin-left: -3px;
border-top: 6px solid rgba(255, 255, 255, 0.5);
border-left: 6px solid transparent;
border-right: 6px solid transparent;
}

Um den Namen des Icons im Stile des Docks anzeigen zu lassen, benötigt man die zwei oberen Einträge. Das Textelement wird absolut positioniert und steht somit nicht mehr in Verbindung mit weiteren Elementen innerhalb des Elternelements. Es wird durch den negativen Wert nach oben geschoben, um bei einer Aktivierung eines Icons noch immer über diesem zu stehen. Der Innenabstand wird gesetzt, die Hintergrundfarbe kann mittels rgba unabhängig vom Text in der Deckkraft verändert werden. Der Wert opacity hätte hier eine Vererbung zur Folge gehabt. Die Schrift wird auf weiss und fett gestellt und erhält einen kleinen Textschatten mit scharfer Kante.
Die zweite Styleangabe arbeitet mit einem Pseudoelement. Hier wird unabhängig vom DOM ein neues sichtbares Element erstellt, welches keinen Inhalt hat. Es wird direkt unterhalb des Namens geschoben und über left und margin-left horizontal zentriert. Das Prinzip von border ist dasselbe wie zuvor bei nav.

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
nav > div > ul {
margin: 0;
padding: 0;
list-style: none;
}

nav > div > ul > li {
display: inline;
margin-right: -4px;
}

nav > div > ul > li:last-child {
margin-right: 0px;
}

nav > div > ul > li img {
width: 50px;
}

Als nächstes kommen die ungeordneten Listen ul dran. Sie sind Block-Elemente und ordnen sich daher untereinander an. Die zweite Liste ist im HTML-Markup noch nicht zu sehen. Die erste Liste wird dynamisch über JavaScript geklont und der Klon unter der ersten eingefügt. Dazu aber erst später. Um unschöne Formatierungen zu vermeiden, werden die Außen- und Innenabstände auf 0 gesetzt, die Aufzählungszeichen durch list-style: none deaktiviert.
Um die einzelnen Listenelemente nebeneinander darzustellen (sie sind block-Elemente und somit untereinander), kommt erneut display zum Einsatz; es wird auf inline gesetzt. Da noch ein kleiner Seitenabstand zwischen den Listenelementen besteht, erhält jedes einen negativen Seitenabstand nach rechts – die Elemente rücken dichter zusammen.
Das letzte Element verliert diesen Seitenabstand wieder, damit die Maße des Regals zum linken und rechten Icon übereinstimmen.
Danach erhalten die einzelnen Icons eine feste Breite; die Höhe wird im Verhältnis automatisch geändert. Die Bilddateien haben eine Auflösung von 100x100 Pixel und werden jeweils auf 50px reduziert. Während einer späteren Vergrößerung kommt es daher zu keiner Unschärfe.

69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
nav > div:last-child {
height: 12px;
margin-top: -7px;
overflow: hidden;
}

nav > div:last-child > ul > li img {
vertical-align: top;
transform: rotateX(180deg);
-webkit-transform: rotateX(180deg);
filter: blur(2px);
-webkit-filter: blur(2px);
-ms-filter: blur(2px);
-o-filter: blur(2px);
opacity: 0.3;
}

Der vorletzte Punkt ist der geklonte Abschnitt. Da der Abstand zur ersten Liste eine kleine Lücke aufweist, wird dieser durch einen Wert von margin-top geschlossen. Die Höhe muss ebenfalls verringert werden, damit direkt danach durch den Punkt overflow der Teil des geklonten Abschnitts nicht sichtbar ist, der auf Grund der kleineren Höhe aus der Box herausragt.
Damit das Ganze nach einer Spiegelung aussieht, werden die Icons der zweiten Liste durch eine 3D-Transformation auf der x-Achse gedreht. Um den Effekt auf unterschiedlichen Browsern nutzen zu können, müssen aktuell noch Browser-Präfixe genutzt werden. Mit der Zeit und der Einarbeitung solcher Dinge in die unterschiedlichen Browser fallen diese aber nach und nach weg. Selbes gilt für filter. Hierbei wird eine zuvor erwähnte Unschärfe über die Icons gelegt. Trotz Präfix ignoriert der Firefox dies jedoch. Darum behelfen wir uns einem kleinen Trick und nutzen SVG-Filtermethoden. Dies wird in das HTML-Markup geschrieben (siehe Abschnitt HTML). Damit der Filter funktioniert, muss zusätzlich eine Angabe im Dokument bzgl. des style gemacht werden. Eine Angabe im externen Stylesheet führte zu keinem sichtbaren Ergebnis. Der Effekt der Spiegelung wird noch effektiver, indem man die Deckraft runtersetzt.
Die Eigenschaft vertical-align: top hält alle Icons an der oberen Kante, wenn mit der Maus über ein einzelnes Icon gefahren wird und sich dieses vergrößert. Somit ist das grundlegende Aussehen des OS X Dock erreicht.
Zum Schluss werden nur noch die CSS3-Transitionen als Klassen erstellt, damit diese später durch JavaScript/jQuery den richtigen Icons zugeordnet werden können.

85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
.obenNormal {
width: 50px;
margin-top: 0px;
transition: width 0.4s, margin-top 0.4s;
-webkit-transition: width 0.4s, margin-top 0.4s;
}

.oben-0 {
width: 100px;
margin-top: 0px;
transition: width 0.4s, margin-top 0.4s;
-webkit-transition: width 0.4s, margin-top 0.4s;
}

.untenNormal {
width: 50px;
transition: width 0.4s;
-webkit-transition: width 0.4s;
}

.unten-0 {
width: 100px;
transition: width 0.4s;
-webkit-transition: width 0.4s;
}

Insgesamt werden 8 Klassen angelegt. Die Klassen .obenNormal und .untenNormal bringen die Icons wieder in ihren Ausgangszustand zurück. Die Klassen .oben-0 bis .oben-2 dienen der Treppchenbildung (siehe Bild 2/3). Die negativen Werte für margin-top halten die Icons bei unterschiedlichen Größen auf derselben Grundlinie. Somit ist hier ein Wert von mindestens der Hälfte notwendig. Bei den Klassen .unten-0 bis .unten-2 verhält es sich ähnlich, bis auf das der Wert für margin-top wegfällt. Die Transitionen dienen letztendlich der Animation. Webkit-Browser benötigen hier noch ihr Präfix.

JavaScript/jQuery

In diesem letzten Teil zeige ich Euch, wie ihr auf einfache Weise, mit Hilfe der jQuery-Bibliothek die zuvor erstellten Transitionen zum Laufen bringt und Dynamik in das Dock kommt. Hier die ersten Zeilen Code.

1
2
3
97

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$(document).ready(function()
{
// Bereich für Quellcode
});

var cloned = $("nav > div").clone(true);
$("nav > div").after(cloned);

var anzahl = $("nav > div:first-child > ul > li").length;
$("nav > div:first-child").append("<p></p>");

function daten()
{
array2d = new Array();
array2d[0] = new Array();
array2d[1] = new Array();
for(var n = 0; n < anzahl; n++)
{
var name = $("nav > div:first-child > ul > li:eq("+n+") > a > img").attr("alt");
$("nav > div:first-child > p").html(name);
array2d[0][n] = name;
var breite = $("nav > div:first-child > p").width() + parseInt($("nav > div:first-child > p").css("padding-left")) * 2;
array2d[1][n] = breite;
}
return array2d;
}

icon-daten = new Array();
icon-daten = daten();
abstufung = new Array(100, 86, 60, 50);

Zu Beginn muss dem JavaScript-Code das Startzeichen gegeben werden. Dies erzielt man über den Ausdruck in der ersten Zeile. JavaScript benutzt für dieses Zeichen das load-Ereignis. Es wird erst dann ausgelöst, wenn das komplette Dokument geladen ist (also Texte, Bilder, usw.). Meistens kann das Skript aber schon ausgelöst werden, wenn das DOM geladen ist. Genau an diesem Punkt greift ready()von jQuery. Danach folgt der gesamte Code für die Animation. Zuerst wird der komplette div-Container geklont und dessen Klon direkt nach dem Container eingefügt. Diesen brauchen wir, wie zuvor erwähnt, für die Spiegelung. Danach wird ein Textelement am Ende des ersten Containers platziert. Dieser dient den Namen der Icons bzw. den Links. Damit der Name immer mittig über dem jeweiligen Icon zu lesen ist, werden über die Funktion daten() die Breiten aller Namen und dessen Namen selbst in einem zweidimensionalen Array nacheinander über eine for-Schleife abgelegt. Zuerst erstellt man ein eindimensionales Array und legt an der ersten (Arrays sind 0-indexiert) sowie zweiten Position des Arrays erneut jeweils ein Array an. Danach kann über die Schleife mittels der Zählvariable n von 0 bis zum Ende der Listenelemente gezählt werden. Die Anzahl der Listenelemente erhält man über .length. Die Breite berechnet sich aus den Werten der Breite des Textes .width() (Wert ohne "px") und den Innenabständen links und rechts aus der Styleangabe. parseInt() lässt dabei das "px" wegfallen, welches am Ende des Wertes steht, sodass mit dem reinen Integer-Wert gearbeitet werden kann. Das Attribut alt, welches im HTML-Dokument angegeben wurde, wird ausgelesen und an Position n des ersten Arrays hinterlegt. Dessen Breite dementsprechend an derselben Position im zweiten Array. Danach wird das zweidimensionale Array zurückgegeben und in dem globalen Array iconDaten gespeichert.
Und als wenn diese Arrays nicht schon genug wären, lege ich gleich noch ein weiteres an (abstufung[ ]). Dieses dient der Speicherung von 4 Werten. Diese 4 Werte geben die Größe der Icons an, die bei einem mouseenter-Event vergrößert werden und auch sie dienen der Zentrierung des Icon-Namens. Würde man sie während des Events auslesen, müsste man bis zum Ende der Transition warten, um eine korrekte Zentrierung zu ermöglichen und die Anzeige des Namens würde sich verzögern – darum das Array.

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
$("nav > div:first-child > ul > li > a > img").hover(function()
{
var i = $(this).parent().parent().index(),
    a, y;

for(a = 0; a <= 3; a++)
{
y = i + a;
var oben = $("nav > div:first-child > ul > li:eq("+y+") > a > img"),
    unten = $("nav > div:last-child > ul > li:eq("+y+") > a > img"),

if(y > anzahl) break;

if(a < 3)
{
oben.removeClass().addClass("oben-"+a);
unten.removeClass().addClass("unten-"+a);
}
else
{
oben.removeClass().addClass("obenNormal");
unten.removeClass().addClass("untenNormal");
}
}

for(a = 1; a <= 3; a++)
{
y = i - a;
var oben = $("nav > div:first-child > ul > li:eq("+y+") > a > img"),
    unten = $("nav > div:last-child > ul > li:eq("+y+") > a > img"),

if(y < 0) break;

if(a < 3)
{
oben.removeClass().addClass("oben-"+a);
unten.removeClass().addClass("unten-"+a);
}
else
{
oben.removeClass().addClass("obenNormal");
unten.removeClass().addClass("untenNormal");
}
}

Nachdem die notwendigen Daten ausgelesen und abgespeichert wurden, kann man sich mit den eigentlichen mouseenter- und mouseleave-Events beschäftigen. Diese werden durch die jQuery-Methode .hover() kombiniert. Zieht man den Mauszeiger über ein Icon, wird zu Beginn der index ausgelesen. Der Index steht hier für die Position im Elternelement. Würde man den Index des Bildes auslesen, wäre dieser immer 0 (man beachte den 0-Index), da kein weiteres Element im Elternelement vorhanden ist. Die eigentliche Position zueinander findet man über die Listenelemente li. Um dorthin zu gelangen, wird die Methode .parent() zwei Mal aufgerufen. Eine Verkettung ist über den Punktoperator möglich.
Die erste for-Schleife dient der Zuordnung der Klassen zum Element, welches das hover-Ereignis auslöst und zu den zwei Elementen, die rechts von ihm liegen. Zuerst werden alle vorhanden Klassen dem DOM-Objekt entzogen und danach die eine bestimmte Klasse hinzugefügt. Sollte die Schleife höher zählen, als tatsächlich Elemente vorhanden sind, wird sie über die Bedingung if(y > anzahl) break; abgebrochen. Die zweite Schleife bezieht sich auf die zwei Elemente links vom gewählten Element. Hier verhält sich die Abbruchbedingung allerdings umgekehrt; hier geht es darum einen Abbruch zu erzielen, wenn der Wert unter 0 fällt. Die Spiegelung wird ebenfalls in beiden Schleifen berücksichtigt.

72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
var breite = iconDaten[1][i] / 2;

switch(i)
{
case 0:
var pos = abstufung[0] / 2 - breite;
break;
case 1:
var pos = abstufung[0] / 2 + abstufung[1] - breite;
break;
case 2:
var pos = abstufung[0] / 2 + abstufung[1] + abstufung[2] - breite;
break;
case default:
var x = i - 2,
    pos = abstufung[0] / 2 + abstufung[1] + abstufung[2] + x * abstufung[3] - breite;
}
$("nav > div:first-child > p").html(iconDaten[0][i]).css({"left": pos, "display": "block"});
},
function()
{
$("nav > div:first-child > ul > li > a > img").removeClass().addClass("obenNormal");
$("nav > div:last-child > ul > li > a > img").removeClass().addClass("untenNormal");
$("nav > div:first-child > p").css("display", "none");
});

Damit der Name jetzt auch noch angezeigt wird, wird der letzte Schritt im mouseenter-Ereignis abgearbeitet. Zuerst wird die Breite des jeweiligen Namens in einer Variable gespeichert. Name und Icon liegen im Moment noch an derselben vertikalen Linie. Über die bedingte Anweisung switch wird ebenfalls wieder auf den Index regiert. Sollte man sich mit der Maus über dem ersten Icon befinden, genügt es den ersten Wert des Arrays abstufung[ ] auszulesen und zu halbieren. Verschiebt man den Namen mit diesem Wert nach rechts, würde das Textelement auf der Hälfte des Icons beginnen. Aus diesem Grund wurde die Breite des Textelements ebenfalls halbiert. Zieht man diesen Wert von der Hälfte des Array-Wertes ab, rutscht der Name wieder ein wenig nach links und zentriert sich über dem Icon. Steht die Maus über dem zweiten Icon, kommt zu diesem Wert der zweite Wert des Arrays hinzu und so weiter. Vielleicht ein kleines Beispiel an dieser Stelle:
Die Maus steht über dem 6. Icon. Das bedeutet, dass die ersten zwei Icons davor (4 und 5) ebenfalls etwas vergrößert werden. Die Icons 1, 2 und 3 behalten ihre normale Größe. Da der Index des 6. Icons 7 ist, wird in der bedingten Anweisung der Wert default genutzt. Somit rechnet man
50 (6. Icon → 100 / 2) + 86 (5. Icon) + 60 (4. Icon) + 150 (3., 2., 1. Icon → 3 * 50) – halbe Breite des Textelements = zentrierte Position über dem 6. Icon Jetzt sollte es etwas deutlicher geworden sein.
Wichtig! Der Abstand zwischen den Icons muss bei dieser Berechnung 0 betragen. Außerdem bekommt man dann auch einen nahtlosen Übergang mit der Maus.
Ist die Berechnung abgeschlossen, wird dem Textelement der Name sowie die Entfernung zum linken Rand des Elternelements übergeben und das Textelement über die Eigenschaft display eingeblendet.
Der letzte Schritt in der Animation ist das mouseleave-Event, also die zweite Funktion in .hover(). Hier wird reagiert, sobald der Mauszeiger das Icon verlässt. Der Name wird ausgeblendet, den Icons werden die Klassen zur Vergrößerung wieder entzogen und erhalten die Klasse des Ausgangszustandes.

Schlussbemerkungen

Ich hoffe, Dir gefällt mein erstes Tutorial. Es ist ziemlich umfangreich geworden. Das war aber meine Intention. So können auch Anfänger, die hierüber stolpern, einiges lernen. Ich werde auf jedenfall in nächster Zeit meine Seite umstellen und einen Blog, mit der Möglichkeit Kommentare zu schreiben, integrieren, um sich direkt austauschen zu können. Das benötigt aber noch etwas Zeit. Bis dahin könnt ihr mich zum Beispiel über Facebook oder Twitter erreichen oder aber über mein Kontaktformular.

  Schau dir die Demonstration an