Vor Kurzem hat mich ein aufmerksamer Leser darauf hingewiesen,
dass der Javascript-Code, den ich im
Blog-Kalender Marke 'Eigenbau' via AJAX
geschrieben habe, verbesserungswürdig sei. Recht hat er, auch wenn es nur
eine Kleinigkeit ist. Sein Kommentar bezüglich des Tabellenkonstrukts jedoch
hat mich angestachelt dieses nicht nur zu überdenken, sondern die Tabelle
komplett durch Block-Elemente zu ersetzen und die gesamte Struktur mittels CSS tabellenartig zu
formatieren.
Mit CSS eine Tabelle nachzustellen ist gar nicht so komplex, wie man
vielleicht meint. Man macht
sich dabei lediglich zu nutze, dass z.B. Inline-Elemente wie Text, Span-Elemente,
et cetera, standardmäßig nebeneinander dargestellt werden. Hat nun der den
einzelnen "Zellen" übergeordnete Container eine festgelegte Breite und
passen nicht alle Zellen nebeneinander, so werden die "überschüssigen"
Elemente
in einer zweiten oder dritten Zeile dargestellt.
Den gleichen Effekt erreicht man, wenn man Block-Elemente wie DIV's
verwendet und Ihnen per CSS das "floaten" (fliessen) z.B. über die Eigenschaft
float:left beibringt.
Beispiel:
CSS-Code
#container {
width: 100px;
height: 50px;
border: 1px solid #FF0000
}
.zelle {
float: left;
width: 23px;
height: 23px;
border: 1px solid #0000FF
}
HTML-Code
<div id="container">
<div class="zelle"> </div>
<div class="zelle"> </div>
<div class="zelle"> </div>
<div class="zelle"> </div>
<div class="zelle"> </div>
</div>
Damit man die Zellen des Beispiels sieht, haben Sie einen 1 Pixel breiten
Rand und wir sind damit schon gleich auf eines der markantesten
Probleme beim Design von CSS-Layouts gestoßen: der unterschiedlichen
Interpretation des Box-Modells der Browser. Während Firefox und andere
moderne Browser die Breite einer Box gemäß der W3C-Spezifikation zuzüglich
aller Polster, Abstände und Rahmen verstehen, sträubt sich der Microsoft
Internet Explorer auch in der aktuellen Beta der Version 7 diesen Standard
anzuerkennen. Dem Beispiel nach sollten alle Zellen eine Gesamtbreite von 25
Pixel haben (23 Pixel Breite plus je ein Pixel für den linken und den
rechten Rahmen). Die Gesamtbreite der Zellen im IE beträgt aber nur 23
Pixel, also die definierte Breite.

Wie man sieht, werden die einzelnen Block-Elemente wie oben erwähnt umgebrochen, womit
Zellen einer Tabelle entstehen. Das Problem mit dem Internet Explorer muss
man jedoch bei diesem Entwurf in Kauf nehmen, bzw. auf diverse sog. Hacks
zurückgreifen, die den Browser austricksen und ihn zur korrekte Anzeige
zwingen. Der bekannteste Hack dieser Art ist der
sog.
Tantek-Hack.
Aber weiter mit dem Kalender: Die Struktur des neuen Kalenders besteht aus einem
DIV-Container,
der neben drei Kopfzellen, die den Titel und die beiden Navigationselemente
aufnehmen, eine Inhaltszelle besitzt, die wiederum als Container für alle
Tageszellen dient. Zusätzlich zum alten Entwurf wurde eine weitere Kopfzeile
eingefügt, die die Namen der Wochentage in verkürzter Notation aufnimmt.
<div id="container">
<div id="kopfzelle1">Navigationselement "vorhergehender Monat"</div>
<div id="kopfzelle2">Monatsname</div>
<div id="kopfzelle3">Navigationselement "nächster Monat"</div>
<div>
<div class="wochentagszelle">Mo</div>
<div class="wochentagszelle">Di</div>
<div class="wochentagszelle">Mi</div>
...
<div class="tageszelle">Tag 1</div>
<div class="tageszelle">Tag 2</div>
<div class="tageszelle">Tag 3</div>
...
</div>
</div>
Wie bereits im vorangegangenen Artikel beschrieben, basiert der AJAX-Kalender auf 3
verschiedenen Javascript-Funktionen, die jeweils eine Teilaufgabe bei der
Erstellung erfüllen. Die erste Funktion createCalendar erzeugt
lediglich den Rahmen, also die Tabellenstruktur. Die zweite Funktion
getCalendar ermittelt via AJAX aus einer Datenbank die Informationen
für einen Monat, also an welchen Tagen Einträge geschrieben wurden. Die
dritte Funktion schließlich, fillCalendar, füllt die
Tabellenstruktur anhand dieser Daten und der Monatsstruktur mit Leben.
Auf der Grundlage des neuen Entwurfs sieht die Javascript-Funktion
createCalendar nun etwas
anders aus.
function createCalendar()
{
var sHTML;
var i;
// Tabellen-Code zusammenstellen
sHTML = '<div id="calendar">'
sHTML += ' <div id="calprev"> </div>'
sHTML += ' <div id="caltitle"> </div>'
sHTML += ' <div id="calnext"> </div>'
sHTML += ' <div>'
sHTML += ' <div class="wd">Mo</div>'
sHTML += ' <div class="wd">Di</div>'
sHTML += ' <div class="wd">Mi</div>'
sHTML += ' <div class="wd">Do</div>'
sHTML += ' <div class="wd">Fr</div>'
sHTML += ' <div class="wd">Sa</div>'
sHTML += ' <div class="wd">So</div>'
// Tabelle mit 6 Zeilen und 7 Spalten erstellen
for(i = 1; i <= 42; i++) {
sHTML += '<div class="d" id="calCell' + i + '"> </div>'
}
sHTML += ' </div>'
sHTML += '</div>'
// Kalender ausgeben
document.write(sHTML);
}
Die Restwertberechnung, um den Beginn der nächste Zeile zu ermitteln, ist nun nicht
mehr nötig, da alle Zellen ja direkt hintereinander weg geschrieben werden.
Es werden jedoch wie zuvor 42 Zellen in 6 Zeilen erstellt, um auch Monate
abdecken zu können, die sich über 6 Wochen erstrecken, wie z.B. der Januar
2006.
An der Funktion getCalendar hat sich nichts geändert. Es
werden schließlich immer noch die gleichen Daten benötigt. Die alles
entscheidende Funktion fillCalendar, die sämtliche Daten in die
Tabellenstruktur füllt, bleibt im Großen und Ganzen auch so wie sie ist,
denn in der neuen Struktur sind die gleichen Zugriffs-ID's vorhanden und
diese werden über die Methode getElementById angesteuert und über die
Eigenschaft innerHTML befüllt. Es ist lediglich eine neue
Unterroutine hinzugekommen, die der Zelle des aktuellen Tages eine weitere
CSS-Klasse zuweist, um sie farblich von den anderen abzuheben. Zudem haben
sich gegenüber der letzten Version die Zugriffs-ID's der Kopfzellen
namentlich geändert.
Alle drei Funktionen sind in der Datei ajax_calendar2.js enthalten,
die weiter unten heruntergeladen werden kann.
Im HTML-Code werden die Funktionen wie folgt eingebunden:
...
<script type="text/javascript">createCalendar();</script>
<script type="text/javascript">getCalendar();</script>
...
Mit createCalendar wird einmalig die Struktur erzeugt und
mit getCalendar die Befüllung angestoßen, wobei hier die
Parameter nicht notwendig sind, da dann automatisch der aktuelle Monat
erstellt wird.
Nachdem die Scripts nun den HTML-Code erzeugen, muss dieser noch mittels CSS
zu einer Tabelle formatiert werden. Als Gesamtbreite wird in diesem Beispiel von 112
Pixeln ausgegangen, also 7 Spalten á 16 Pixel. Die beiden äußeren Kopfzellen
sind ebenfalls 16 Pixel breit und die mittlere Kopfzelle muss demnach 80 Pixel breit werden.
Die Höhe des Containers errechnet sich aus den Zeilenhöhen der Kopfzellen
und der Tageszellen, die alle 18px hoch sind. Bei insgesamt 8 Zeilen sind
das 144 Pixel.
/* Breite und Höhe des Kalender-Containers festlegen */
#calendar {
width: 112px;
height: 144px;
}
/* Standardformatierung für alle DIV's innerhalb des Kalenders */
#calendar div {
float: left;
font-family: arial, sans-serif;
font-size: 8pt;
text-align: center;
line-height: 18px;
}
/* Kalender-Links */
#calendar a { text-decoration: none; }
#calendar a:hover { text-decoration: underline; }
/* Kopfzelle 1 */
#calprev {
width: 16px;
font-size: 14px;
text-align: left;
}
/* Kopfzelle 2 */
#caltitle {
text-align: center;
width: 80px;
}
/* Kopfzelle 3 */
#calnext {
width: 16px;
font-size: 14px;
text-align: right;
}
/* Wochentag-Zellen */
#calendar .wd {
width: 16px;
color: #94A2A5;
}
/* Tageszellen */
#calendar .d { width: 16px; }
/* Tageszelle Heute */
#calendar .td { background-color: #E2E2E2; }
Wie man sieht, geht das Ganze auch ohne Tabellen, auch wenn man hier mit
dem Box-Model-Bug des Internet Explorers leben muss. Dieses Manko erscheint
aber nicht so gravierend, denn auch beim Tabellenkonstrukt kann es zu
unterschiedlichem Aussehen je nach verwendetem Browser kommen.
Downloads
ajax_calendar2.js