Zur „HTML5-ist-noch-nicht-fertig-Debatte“

Veröffentlicht am 11. Oktober 2010

Im Moment werden aus mir unbekannten Gründen an allen Ecken und Enden des Webs Traktate darüber geschrieben, ob/wann/inwiefern HTML5 „fertig“ oder „einsetzbar“ ist. Dabei ist die Lage eigentlich ganz simpel: HTML5 (was immer man darunter auch versteht) ist in der Tat nicht „fertig“ im Sinne eines Webstandards wie etwa HTML 4.01. Es ist allerdings auch nicht vorgesehen, dass HTML5 je in diesem Sinne „fertig“ sein wird! Der momentane Plan ist, dass es nie ein HTML 6 geben wird, sondern dass alle Neuerungen, die sich die Browserhersteller so ausdenken, nahtlos in HTML5 einfließen – in dem Maße, in dem einige Teile von HTML5 stabiler werden, werden also immer wieder neue Baustellen aufgemacht. HTML5 ist prinzipbedingt nicht „fertig“ und wird es nie sein! Ob und wann man es in Teilen einsetzt, sei jedem selbst überlassen, aber klar ist: vom Abwarten wird es auf keinen Fall besser, stabiler oder fertiger.

„Chroma Corners“ – Fast perfekte runde Ecken im Internet Explorer

Veröffentlicht am 4. Oktober 2010

Ein Gastbeitrag von Christian „Schepp“ Schaefer

Runde Ecken im Internet Explorer – das ist ein Thema, das uns jahrelang beschäftigt hat, um das es aber nahezu still geworden ist, da sich mittlerweile einige Techniken zur Simulation derselben als Best-Practices herausgeschält haben. Heute stelle ich Euch eine neue Technik vor.

Welche Techniken stehen denn bisher zur Auswahl?

Ignorieren

Man zieht sich auf den Standpunkt des „Progressive Enhancements“ zurück und kümmert sich erst gar nicht um eine Lösung für den IE.

Die „Mountaintop Corners“

Vorteil: Schnelle Farbänderungen am Objekt selbst sind problemlos möglich
Nachteil 1: Keine Eckentransparenz, funktioniert also nicht auf texturierten Seitenhintergründen, sondern nur auf flächigen, einfarbigen.
Nachteil 2: Für jede Farbänderung des Hintergrunds müssen neue Eck-Grafiken erstellt werden

„Sliding Doors“ Verfahren

Vorteil: Volle Eckentransparenz, funktioniert also auf texturierten Seitenhintergründen
Nachteil 1: Für jede Farbänderung am Objekt selbst müssen neue Grafiken erstellt werden
Nachteil 2: Nicht in zwei Achsen gleichzeitig flexibel dimensionierbar

VML Image Replacement

Dieses Verfahren ist das Jüngste von allen, und erfährt gerade in der letzten Zeit durch JavaScript-Extensions à la CSS3-PIE eine hohe Aufmerksamkeit. Hierbei wird per JavaScript oder IE-Behavior/.htc-Datei ein Script in die Seite eingebunden, das nach dem Laden der Seite die Stylesheets nach border-radius-Anweisungen durchforstet und HTML-Elemente mit dieser Eigenschaft durch on-the-fly-berechnete VML-Vektorgrafiken ersetzt (vergleichbar mit sFIR oder cúfon).

Vorteile:

  • Eckentransparenz, funktioniert also auf texturierten Seitenhintergründen
  • Hintergrund des Objekts muss nicht einfarbig sein
  • Flexibel dimensionierbar
  • Schnelle Farbänderungen möglich

Nachteile:

  • Arbeitete in den ursprünglichen Implementierungen statisch, reagiert also nicht auf Farb- oder Dimensionsänderungen beim Hover-Zustand, geschweige denn durch dynamisches Scripting.
  • Zieht die Renderperformance des Browser stark in den Keller.
  • Und weitere Nachteile

Wir stellen fest: Jede Technik für sich hat ganz spezifische Vor- und Nachteile. Die VML-Methode bedeutet für uns Webentwickler die wenigste Arbeit, fügt sich aber nicht in den bekannten Seitenkontext ein, bleibt unberechenbar und unperformant. Die Arbeit mit Grafiken dagegen ist berechenbarer und performant (wenn man mal HTTP-Requests ausblendet), ist jedoch unflexibel und arbeitsintensiv.

Müssen wir uns damit zufrieden geben? Haben wir keine besseren Methoden?

Doch, die haben wir! Wir bedienen uns dazu des mehr oder minder im Dornröschenschlaf befindlichen proprietären IE-Chroma-Filters.

Greenscreening im Browser

Den Chroma-Filter muss man sich wie einen Color-Keyer vorstellen, der alle Bereiche eines Objekts, die in einer speziellen Farbe eingefärbt sind, aus diesem herausstanzt. Das Ganze ähnelt also den Bluebox- oder Greenscreen-Verfahren bei Film und Fernsehen, bei denen Darsteller vor einfarbigen Leinwänden agieren, die dann transparent gemacht werden und eine virtuelle Szenerie durchscheinen lassen.

Green Screen Tutorial Video

Mit folgendem Code können wir veranlassen, dass alle cyanfarbenen Teile eines Objekts transparent werden:

filter: progid:DXImageTransform.Microsoft.Chroma(color='cyan'); /* IE 6/7 Syntax */
-ms-filter: "progid:DXImageTransform.Microsoft.Chroma(color='cyan')"; /* IE 8 Syntax */

Anstatt „cyan“ könnte man auch #00FFFF schreiben, und Cyan wurde als Farbe gewählt, weil kein Mensch mit klarem Verstand diese Farbe auf seiner Seite einsetzen würde.

Das Interessante am Chroma Filter ist, dass er auch solche Farbflächen beim Ausstanzen berücksichtigt, welche von Kindelementen des den Chroma-Filter-tragenden Elements stammen.

Deshalb könnte man ein Art roten Rahmen mit 10px Breite mit folgendem HTML erzeugen:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Chroma Demo</title>
	<style>
	.foo {
		width: 120px;
		background-color: red;
                filter: progid:DXImageTransform.Microsoft.Chroma(color='cyan'); /* IE 6/7 Syntax */
		-ms-filter: "progid:DXImageTransform.Microsoft.Chroma(color='cyan')"; /* IE 8 Syntax */
	}
	.bar {
		height: 100px;
		margin: 10px;
		background-color: cyan;
	}
	</style>
</head>
<body>
	<div class="foo">
		<div class="bar"></div>
	</div>
</body>
</html>

Die komplette Fläche von .bar würde aus dem Filter-tragenden .foo herausgestanzt, da vollständig cyanfarben, und man könnte in der Mitte durchgucken.

Das wollen wir nun für unsere Runden Ecken weiter ausbauen. Wir erstellen eine Hintergrundgrafik von 2048 × 2048 in Photoshop, die voll transparent ist, bei der nur die Bereiche in den vier Ecken cyanfarben eingefärbt sind, welche den Bereich außerhalb der runden Ecken liegend darstellen (also das, was ich später ausstanzen will):

Dann erstelle ich das Objekt, dessen Ecken ich gerne rund hätte, indem ich einige DIVs ineinander verschachtele…

<div class="chroma_base">
	<div class="chroma_topleft">
		<div class="chroma_topright">
			<div class="chroma_bottomright">
				<div class="chroma_bottomleft">Drag me!</div>
			</div>
		</div>
	</div>
</div>

…um dann meine Hintergrundgrafik .chroma_topleft bis .chroma_bottomleft zuzuweisen, jeweils mit unterschiedlicher Positionsverankerung:

.chroma_topleft,
.chroma_topright,
.chroma_bottomright,
.chroma_bottomleft {
	background-image: url(chroma14px.gif);
	background-color: transparent;
	background-repeat: no-repeat;
}
.chroma_topleft {background-position: left top;}
.chroma_topright {background-position: right top;}
.chroma_bottomright {background-position: right bottom;}
.chroma_bottomleft {background-position: left bottom;}

(Anmerkung: Die obigen Anweisungen sollte man per Conditional Comments ausschließlich den IEs <= 8 servieren)

Der aktuelle Zwischenstand (rechte Seite zu Illustrationszwecken abgedunkelt):

.chroma_base bekommt als Root-Element den Chroma-Filter und ein position: relative; (oder absolute), damit alles in den älteren IEs sauber funktioniert. Dazu all die Styles, die mein Objekt abseits der Runden Ecken noch so haben soll, zum Beispiel Ausmaße und ein Hintergrundbild:

.chroma_base {
	position: relative; /* Needed for IE 6/7 */

	width: 200px;
	line-height: 50px;
	text-align: center;
	background: #600118 url(gradientdark.png) repeat-x left top;
	color: #FFF;

	-moz-border-radius: 14px;
	-webkit-border-radius: 14px;
	border-radius: 14px;

	filter: progid:DXImageTransform.Microsoft.Chroma(color='cyan'); /* IE 6/7 Syntax */
        -ms-filter: "progid:DXImageTransform.Microsoft.Chroma(color='cyan')"; /* IE 8 Syntax */
}

Fertig ist die Laube und heraus kommt dies:

Das Schöne dabei ist: nun kann man jederzeit hingehen und nicht nur die Ausmaße sondern auch den Hintergrund ändern, alles ausschließlich per CSS, ohne Rückgriff auf Photoshop. Desweiteren beobachte ich, dass wenn Seiten einen border-radius einsetzen, dass dieser aus Konsistenzgründen meist seitenweit denselben Radius hat. Ergo erschlägt man möglicherweise mit dieser einen Photoshop-Grafik direkt alle Fälle von border-radius auf seiner Seite.

Die Lösung funktioniert sogar, wenn sowohl Seitenhintergrund als auch Objekthintergrund strukturierte Texturen sind. Und sie beißt sich auch nicht mit dynamischen Effekten à la Hover.

Funktioniert das denn auch mit einem Border?

Ja, das tut es! Dazu muss man allerdings die Grafik anpassen, wie auch noch ein paar Styles hinzufügen. Und wir verlieren etwas an Flexibilität und Eleganz.

Legen wir mal einen soliden Border von 2px Breite in der Farbe #808080 zugrunde. Die Grafik müssen wir dann an den Ecken folgendermaßen ergänzen:

Dem Root-Element geben wir diesen Border per CSS:

.chroma_base {
	border: #808080 2px solid;
}

Darüber hinaus müssen wir dem ersten Kind-Element noch Styles überbügeln, die es über den, das Root-Element umgebenden Rahmen schieben lässt.

Für alle IE (per Conditional Comments):

.chroma_topleft {
	margin: -2px; /* root border-width * (-1) */
}

Und zusätzlich für IE6 und IE7 (ebenfalls per Conditional Comments):

.chroma_base * {
	position: relative; /* Needed so that border-overlaping works in IE 6/7 */
	width: 204px; /* root width + (2 * root border-width) */
}

Zusammen mit einem helleren Hintergrund ergibt das folgendes Resultat:

Ebenfalls kann man hier jederzeit nicht nur die Ausmaße sondern auch den Hintergrund ändern, ohne Photoshop starten zu müssen. Die Bildbearbeitung müssen wir allerdings dann bemühen, wenn wir die Border-Farbe ändern wollen, da sie in der Chroma-Grafik fest „verdrahtet“ ist. Wir verlieren in der Border-Variante zudem die Option, dem Element eine fluide (%) Breite zu verpassen, zumindest wenn sie in IE6 und 7 funktionieren soll.

Ich nenne die Technik die „Chroma Corners“ und habe Euch ein Live-Beispiel unter folgender Adresse abgelegt:
http://www.peterkroener.de/test/chroma/ (Download ZIP).

Desweiteren habe ich das Ganze in ein kleines Softwarepaket gegossen, das aus einer proprietären IE-Behavior (.htc) und einem PHP-Script zur automatischen Generierung der Eckgrafiken besteht, die sich zusammen um all das Beschriebene kümmern – für Euch also kein Handschlag mehr zu tun als dies (mit angepastem .htc-Pfad):

-moz-border-radius: 14px;
-webkit-border-radius: 14px;
border-radius: 14px;
behavior: url(chromacorners.htc); /* relative path from HTML-file! */

Und zu guter letzt liegt darauf basierend auch schon ein Turbine-Plugin bereit, das in das nächste Release hineinwandern wird.

Über den Autor

ScheppChristian Schaefer ist Jahrgang '78, hat seine Wurzeln bei Köln, lebt seit 2004 unbehelligt in Düsseldorf, und wird von jedermann außer den Eltern „Schepp“ genannt. Und das ist auch gut so. Es verschlug ihn 1998 ohne Studium direkt in eine 3D-Firma in Köln. Dort entwickelte er virtuelle Figuren für Messen und TV. Selbstständigmachung Anfang 2004 und Verlagerung des Fokus' auf die Webentwicklung. Sieht seine Schwerpunkte bei der Frontend-Entwicklung, hat aber auch kein Problem mit Backends und dem Architekten großer Sites in PHP und MySQL. Fertige CMSe nerven ihn. Frameworks sind OK. Nebenbei unterstützt er technisch den Kölner Multimediatreff, hat gerade ein Videotraining biblischen Ausmaßes fertiggestellt. Er twittert unter dem Account derSchepp und mag alles was sich um Essen dreht.

Schönes neues CSS: border-image

Veröffentlicht am 27. September 2010

Auf vielfachen Wunsch hin wird die Serie schönes neues CSS wird weiter fortgesetzt. Heute auf dem Programm: border-image. Hierbei handelt es sich wieder um ein CSS3-Feature, das keine neuen Effekte o.Ä. ermöglicht, aber uns einiges anderes wesentlich einfacher (d.h. mit weniger HTML-Overhead und besserer Performance) umsetzen lässt. Das Ganze ist ein wenig komplexer als manch andere CSS3-Neuheit, aber für einen kurzen Überblick reicht ein Blogpost allemal.

Was macht border-image?

Der Name sagt es eigentlich schon: border-image erlaubt es uns, unkompliziert Grafiken für Rahmen einzusetzen. Was das praktisch bewirkt, lässt sich am besten an einem Beispiel erklären. Man stelle sich vor, wir wollten ein Interface mit HTML und CSS bauen, dessen Elemente einen solchen Rahmen tragen sollen:

Ein Interface

Oben gibt es eine Titelleiste, rundherum ein Rahmen und der weiße Bereich in der Mitte ist für den Inhalt vorgesehen. Die Maße des Elements sollen dabei variabel sein. Mit herkömmlichem CSS ist hier nichts wirklich sinnvolles zu machen – Man müsste diese Grafik zerschneiden, viele  <div>-Elemente ineinander verschachteln und diesen die verschiedenen Grafik-Schnipsel als Hintergrundbilder verpassen. Das alles wäre nicht nur umständlich, sondern aufgrund der vielen Grafikschnipsel schlecht für die Performance. Abhilfe verspricht die neue CSS3-Eigenschaft border-image.

Wie funktioniert border-image?

Man kann sich border-image in etwa wie CSS-Sprites mit eingebautem Autopilot vorstellen. Für eine einzige Grafik, die den gesamten Rahmen beinhaltet lässt sich angeben, welche Ausschnitte davon Ecken und Rahmen sind. Außerdem es lässt sich festlegen, wie die Rahmen konstruiert werden sollen, also ob ein Grafik-Ausschnitt gestreckt oder wiederholt werden soll. Für unser Interface sähe die gewünschte Segmentierung wie folgt aus:

Interface mit Segmenten

Die blau markierten Segmente sollen gekachelt werden, die Grünen können ihre Fläche durch Strecken füllen und die Eck-Segmente sollen einfach in den Ecken stehen. Klingt kompliziert, ist aber mit border-image eine Fingerübung:

#foo {
    border-width: 64px;
    border-image: url(interface.png) 64 64 64 64 stretch repeat;
}

Funktioniert! Zur Erläuterung:

  • border-width:64px; sorgt für die gewünschte Rahmenbreite
  • url(interface.png) in border-image gibt das zu verwendende Bild an
  • 64 64 64 64 definiert die Maße der Ausschnitte (Details siehe weiter unten)
  • stretch repeat legt fest, dass die horizontalen Rahmen aus gestreckten, die vertikalen Rahmen aus gekachelten Grafiken bestehen sollen

Die Ausschnitte können entweder als ganze Zahlen oder Prozente angegeben werden, wobei die Zahlen Pixel in der Grafik repräsentieren (die Angabe der Einheit px ist nicht nötig). Die einzelnen Werte werden als Abstände von Rändern der Grafik interpretiert und wie auch bei margin und padding kann man, wenn mehrere Werte gleich sind, sie von rechts nach links weglassen, so dass Folgendes herauskommt:

#foo {
    border-width: 64px;
    border-image: url(interface.png) 64 stretch repeat;
}

Die Angaben für die Ausschnitte werden wie üblich im Uhrzeigersinn angegeben. So würde die Angabe 25% 30% 12% 20% zur folgenden Segmentierung einer Grafik führen (s. border-image-slice):

border-image-slice-Werte werden im Uhrzeigersinn interpretiert

Dabei ist border-image mehr als nur die CSS-Eigenschaft border-image. Die kompletten Spezifikationen sind recht umfangreich, wobei border-image als selbst nur die Kurzversion für eine Kombination aus border-image-source, border-image-slice, border-image-width, border-image-outset und border-image-repeat. Die vielen nützliche Kleinigkeiten wie z.B. round als Streck/Wiederholmodus für Grafiken (Demo) würden den Umfang dieses Artikels sprengen und wichtiger ist ohnehin die Frage, was man denn mit all dem heute schon anfangen. Wie so oft gibt es hier Licht und insbesondere in der Nähe von Redmond auch eine Portion Schatten.

Welche Browser verstehen border-image?

Mit Opera 10.5+, Firefox 3.5+ und der Webkit-Brigade (ab Engine-Version 522) verstehen die meisten Browser, von denen man es auch erwarten würde, border-image – die beiden letztgenannten noch mit Vendor-Prefix. Problematisch ist nur, dass CSS3, da ja noch nicht fertig, ständig weiterentwickelt wird und jeder Browser unterstützt eine andere Revision von border-image. Um ein und denselben Effekt zu erreichen, muss man also gegebenenfalls mehr machen als nur die Vendor-Prefixes austauschen, in den meisten Fällen reicht jedoch genau das:

#foo {
    width: 400px;
    border-width: 64px; /* Diese Angabe könnte der Firefox auch in seiner -moz-border-image-Eigenschaft unterbringen */
    border-image: url(interface.png) 64 64 64 64 stretch repeat; /* Aktueller Stand der Spezifikationen (von Opera unterstützt) */
    -moz-border-image: url(interface.png) 64 64 64 64 stretch repeat; /* Firefox/Gecko-Browser */
    -webkit-border-image: url(interface.png) 64 64 64 64 stretch repeat; /* Webkit-Browser */
}

Dieser Code führt zwar in den unterstützenden Browsern zum gleichen Ergebnis, aber da den Implementierungen jeweils verschiedene Revisionen von border-image zugrunde liegen, unterstützen nicht alle Browser den gleichen Funktionsumfang. Es gibt große Überschneidungen, aber nicht alles, was in den Spezifikationen steht funktioniert überall (und nicht alles was funktioniert, steht heute noch in den Spezifikationen). Schlimmer noch: der IE9 wird border-image überhaupt nicht unterstützen.

Das Fazit ist also: Je nachdem was man erreichen wollte, könnte man mit border-image schon einiges anstellen, wenn da nur der Internet Explorer nicht wäre. Vernünftige Browser haben bereits brauchbare Implementierungen an Bord, wobei man aber genau nachlesen sollte, welche Browserversion welche Revision der Spezifikationen inwiefern unterstützt.

Wie Otto Normalwebworker HTML5 verbessern kann

Veröffentlicht am 7. September 2010

Ein Strichmännchen

Wann immer ich Klagen höre, eine HTML5-API sei unzureichend in Browsern implementiert oder wäre einfach nur schlimm, denke ich mir: ändere es doch! Man muss kein Browserhersteller sein um HTML5 zu verbessern und man muss sich auch nicht auf Mailinglists von den hohen Herren abwatschen lassen – ein paar Zeilen JavaScript zu schreiben reicht. So ist etwa das HTML5-Element Canvas ein recht unhandliches Teil. Dank seiner etwas web-fremden Low-Level-Konzeption kann man mit einem normalen 2D-Context eigentlich so gut wie gar nichts anfangen, da die API viel zu rudimentär und benutzerunfreundlich ist. Um etwa das oben rechts abgebildete Strichmännchen darzustellen, müsste man das folgende Monstrum konstruieren:

var context = canvas.getContext('2d');
// Pfad beginnen
context.beginPath();
// Körper
context.moveTo(240, 100);
context.lineTo(240, 200);
// Beine
context.lineTo(190, 250);
context.moveTo(240, 200);
context.lineTo(290, 250);
// Arme
context.moveTo(240, 150);
context.lineTo(190, 150);
context.moveTo(240, 150);
context.lineTo(290, 150);
// Linie ziehen
context.lineWidth = 4;
context.strokeStyle = '#CC0000';
context.stroke();
context.closePath();
// Kopf
context.beginPath();
context.arc(240, 80, 35, 0, 6.28318531, false);
// Kopf zeichnen
context.fillStyle = context.strokeStyle;
context.fill();
context.stroke();
context.closePath();

Das ist dann doch recht mühsam. Aber das Canvas-Element ist auch gar nicht dafür gemacht, so direkt eingesetzt zu werden, es ist vielmehr eine Steilvorlage für JavaScript-Bibliotheken. Diese können dann spezialisiertere und/oder etwas leichter zu nutzende APIs umsetzen. So wäre der obrige Code-Brocken doch gleich schon viel angenehmer zu scheiben und zu lesen, wenn die Methoden jQuery-artig verkettet wären:

var context = CanvasQuery('test');
// Körper
context.moveTo(240, 100).lineTo(240, 200);
// Beine
context.lineTo(190, 250).moveTo(240, 200).lineTo(290, 250);
// Arme
context.moveTo(240, 150).lineTo(190, 150).moveTo(240, 150).lineTo(290, 150);
// Linien ziehen
context.set({'lineWidth': 4, 'strokeStyle': '#CC0000'}).stroke().closePath();
// Kopf
context.beginPath().arc(240, 80, 35, context.deg2rad(0), context.deg2rad(360), false);
// Linien ziehen
context.set('fillStyle', context.get('strokeStyle')).fill().stroke().closePath();

Die Canvas-API entsprechend umzubauen ist keine Herkulesaufgabe, nur knappe 60 Zeilen Code sind dafür nötig. Sowas kann jeder halbwegs fähige JavaScript-Nerd schreiben und es könnten auf diese Weise viele nicht nativ in Browsern implementierte HTML5-APIs nachgebaut oder ausgebessert werden, wie etwa die gruselige Drag-&-Drop-API oder die in den meisten Browsern nicht vorhandene API für data-*-Attribute. Ein perfektes Beispiel hierfür ist jStorage, eine kleine JS-Bibliothek, die dafür sorgt, dass eine Website clientseitig Daten speichern kann und sich um die Macken der diversen Browser kümmert.

Von genau dieser Sorte Script braucht die Welt mehr. Die Schlacht um ein besseres HTML5 muss nicht nur in den Arbeitsgruppen von W3C und WHATWG geschlagen werden sondern auch draußen im Web, von uns Webworkern. Wenn den großen Entscheidern mal eine Schnittstelle missrät oder wenn einfach mal etwas nur unzureichend implementiert ist, haben wir selbst es in der Hand, mit etwas JavaScript für eine De-facto-Reparatur zu sorgen. Also frisch ans Werk!