Fortgeschrittene Webtypografie mit Canvas und CSS – CSS3 Adventskalender Tag 21

Die letzten 3 Jahre haben uns Designern aufregende neue Möglichkeiten für die typografische Gestaltung von Schrift im Internet geschenkt. Schriften über @font-face direkt ins Dokument einzubinden ist mittlerweile zur Selbstverständlichkeit geworden, neue CSS Filter und Transformationen haben unser gestalterisches Vokabular entscheidend erweitert. Darüber hinaus versprechen neue CSS Eigenschaften wie „mask-image“ (derzeit nur Webkit) und Javascript Libraries wie lettering.js nie dagewesene Kontrolle über die Schriftdarstellung im Web.

Und trotzdem reichen alle diese Lösungen noch immer bei weitem nicht aus, um an die Grenzen des Möglichen zu kommen. Jeder, der einmal versucht hat, einen HTML-Text mit einem Verlauf zu füllen, weiss wovon ich rede.

Ich möchte hier eine Methode vorstellen, die zu Unrecht noch nicht die Beachtung gefunden hat, die Sie verdient: das Gestalten von Text mit der HTML5 Canvas.

Dass die Canvas über viele aufregende typografische Methoden verfügt, hat sich bisher kaum herumgesprochen. Wahrscheinlich liegt das daran, dass sie bisher eher als Domäne der Spieleentwickler wahrgenommen wurde. Das ist Schade, denn Sie bietet uns Möglichkeiten, die weit über die klassischen Methoden die CSS zu bieten hat hinausgehen und das auch noch in allen modernen Browsern: Verläufe oder Bitmaps in Füllung und Outline, Masken, Schatten, Blendmodes sind nur einige ihrer Methoden.

Ich werde zu Beginn die Textwerkzeuge der Canvas API zu Schriftgestaltung vorstellen und im zweiten Teil zeigen, wie sich diese Methoden nutzen lassen um aufregende, barrierefreie und suchmaschinenfreundliche Webtypografie zu erzeugen.

1. Die Textfunktionen der Canvas

Ich setze voraus, dass Ihr schon wisst wie man eine Canvas in einem HTML Dokument erstellt und anspricht.

Eine bestehende Canvas (wir haben den Kontext wie meist üblich mit „ctx“ bezeichnet) muss zunächst vorbereitet werden. Mit der Anweisung „Font“ legen wir fest, welche Schrift in welcher Größe wir verwenden wollen:

ctx.font = "50px  'Helvetica' ";

Weiterhin müssen wir festlegen, wie die Grundlinie verankert werden soll. Fünf Möglichkeiten stehen zur Auswahl:
top„, „hinging„, „middle„, „alphabetic„, „demographic„, „bottom„. Die Entscheidung fällt uns leicht: bis auf „alphabetic“ werden alle Ausrichtungen von jedem Browser anders interpretiert Die Anweisung lautet somit:

ctx.textBaseline = 'alphabetic';

Für Typografen sicherlich von Interesse ist die Möglichkeit für die gesamte Canvas eine Skalierung festzulegen. Gut zu wissen für den Fall, dass man mal für hochauflösende Displays entwickelt:

ctx.scale(1,1);

Bleibt zu klären, wie wir unseren Text füllen möchten. Zur Auswahl stehen solide Farben, Verläufe oder Bitmap-Muster. Der Einfachheit halber starten wir mal mit einer Farbe:

ctx.fillStyle = "#ff0000";

Die einfachste Methode, Text in eine bestehende Canvas zu schreiben ist die Methode „fillText„. Die folgende Methode schreibt „Hallo Welt“ in die Canvas, 50px von rechts und eine 100px von oben verschobene Grundlinie:

ctx.fillText("Hallo Welt", 50, 100);

Neben der „fillText“ Methode können mit der Methode „textStroke“ auch Umrisslinien gezeichnet werden:

ctx.lineWidth = 3;
ctx.strokeStyle = "#0000ff";
ctx.textStroke("Hallo Welt", 50, 100);

Verläufe

Um anstelle einer soliden Farbe eine Verlaufsfüllung zu verwenden, muss diese vorher definiert werden. Das geschieht in 2 Schritten:

1: Start- und Endpunkt festlegen:

var gradient = ctx.createLinearGradient(0, 0, 200, 50);

Hier haben wir einen Verlauf mit dem Startpunkt (x:0, y:0) und dem Endpunkt (x:200, y: 50) definiert.

2. Color-Stops hinzufügen.

So sähe es aus, wenn wir einen Verlauf von weiss(0%) nach schwarz(50%) nach rot(100%) festlegen wollten:

gradient.addColorStop(0, 'white');
gradient.addColorStop(0.5, 'black');
gradient.addColorStop(1, 'red');

Bitmapfüllungen

Bitmaps können ebenfalls als Füllungen verwendet werden. In dem meisten Fällen wird man ein jpg oder png verwenden, aber es lassen sich auch interessante Effekte erzielen, indem man dynamisch in einer Canvas generierte Bilder als Füllung einsetzt.

var img = new Image(),pattern;
img.src	= "img/myimage.jpg";		
img.onload = function(){
  pattern = ctx.createPattern(img, "repeat");
}

Hier ist zu beachten, dass wir unbedingt warten müssen bis das Bild vom Server geladen wurde, bevor wir das Muster in der Canvas verwenden.

Das schöne an Verläufen und Mustern ist, dass Sie nicht nur in Textfüllungen sondern auch auf Outlines verwendet werden können. Es lassen sich somit einige beeindruckende Effekte erzielen:

ctx.strokeStyle = gradient;
ctx.strokeText("Hallo Welt", 50, 100);
ctx.fillStyle = pattern;
ctx.fillText("Hallo Welt", 50, 100);

Schatten

Die Canvas bietet auch die Möglichkeit, Schatten zu erzeugen. Ein Schatten mit 50% Opazität, 5px Versatz und einem Blur von 7 Pixeln sieht so aus:

ctx.shadowColor = “rgba(0,0,0,0.5)”;
ctx.shadowOffsetX = 5; 
ctx.shadowOffsetY = 5; 
ctx.shadowBlur = 7;

Wurde dem Kontext einmal Schatten zugewiesen, wird dieser fortan auf alle weiteren Zeichenoperationen angewendet. Wenn man ihn nicht mehr benötigt, sollte man ihn deswegen zurücksetzen:

ctx.shadowColor		= "rgba(0,0,0,0)";
ctx.shadowOffsetX 	= 0;
ctx.shadowOffsetY 	= 0;
ctx.shadowBlur 		= 0; 

Bei dieser kurzen Übersicht über die gängigsten Textzeichenmethoden der Canvas möchte ich es hier belassen. Leider konnte ich nur an der Oberfläche kratzen, welche Vielfalt an Möglichkeiten darüber hinaus bestehen. So lassen sich z. B. mit der Methode globalCompositeOperation BlendModes für Zeichenvorgänge festlegen, die Methode clip() erlaubt es uns, Shapes als Masken zu verwenden. Gute weiterführende Infos finden sich natürlich bei Mozilla und in der Safari Developer Library.

Canvas mit CSS verbinden:

Wir haben gelernt, wie die Canvas genutzt werden kann um Texte mit einer Vielzahl von Effekten zu versehen. Leider ist die Canvas eine semantisch bedeutungslose Ansammlung von Pixeln. Textliche Inhalte sind von aussen nicht lesbar und eine Trennung von Präsentations- und Inhaltsebene findet nicht statt. Wie können wir die Möglichkeiten der Canvas innerhalb eines HTML Dokumentes so einsetzen, dass Semantik und Maschinenlesbarkeit eines Textes erhalten bleiben? Wie lässt sich Barrierefreiheit erzielen?

Nachdem ich nun schon einige Male mit dieser Methode in Berührung gekommen bin, hat sich für mich der folgende Weg als der praktikabelste herausgestellt:

  1. Ermittle den Textinhalt und die Textmetrik des Elementes dessen Typografie verändert werden soll.
  2. Erstelle die Canvas Grafik mit dem ermittelten Text.
  3. Weise dem Element die Grafik als Hintergrundbild zu
  4. Mach den HTML Text des Elementes transparent, damit er nicht mehr zu sehen ist, aber selektiert und kopiert werden kann und für Crawler und Screenreader zur Verfügung steht

EIn Beispiel macht den Prozess verständlich: nehmen wir an, auf einer Website befindet sich eine <h2> der folgender CSS Stil zugewiesen ist:

#headline{
	font-family: 'Helvetics', sans-serif; 
	font-size: 40px;
}

zuerst ermitteln wir Stileigenschaften und Textinhalt:

var elem = documentGetElementById("headline"),
    text = elem.textContent,
    style = document.defaultView.getComputedStyle(elem, null),
    font = style.getPropertyValue("font-family").match(/^[^,]*/gi).replace(/['"]*/gfont,""),
    size = parseFloat(style.getPropertyValue("font-size")),
    topPadding=parseFloat(style.getPropertyValue("padding-top")),
    leftPadding=parseFloat(style.getPropertyValue("padding-left"));

Jetzt wird’s kompliziert: damit wir den Text in der Canvas deckungsgleich mit dem HTML Text auf dieselbe Grundlinie setzen können, müssen wir diese Grundlinie mit einem komplizierten Trick ermitteln. Ich werde nur kurz beschreiben, wie die Technik funktioniert, wer mehr wissen will, sollte am besten die Source zu diesem Beispiel studieren:

Zuerst müssen wir mit Javascript ein Element mit denselben Texteigenschaften wie unser <h2> ins Dokument schreiben, In dieses Element hängen wir nun ein 1 x 1 Pixel Bild mit der CSS-Eigenschaft vertical-align: baseline. Wir lesen die offsetTop Eigenschaft dieses Bildes aus und haben mit diesem Wert auch die Position der Baseline. Natürlich entfernen wir unsere Testelemente nachher wieder ordentlich.

Nun können wir die Canvas erstellen und der <h2> als Hintergrundbild zuordnen:

var canvas = document.createElement("canvas"),
    top = topPadding+height;

if (this.canvas.getContext) {
  var ctx = canvas.getContext('2d');
  ctx.font = size+"px '"+font+"'";
  ctx.textBaseline = 'alphabetic';
  ctx.scale(1,1);
  ctx.fillStyle = "green";
  ctx.fillText (txt, Padding, top);

  var img = canvas.toDataURL();
  elem.style.color="rgba(0,0,0,0.0)";
  elem.style.backgroundImage="url("+img+")";
}

Im vorliegenden Fall wurde eine einfarbige Schrift durch eine einfarbige Schrift ersetzt. Das macht natürlich außer zu Demonstrationszwecken keinen Sinn.

Diese kleine Galerie zeigt aber, welche Möglichkeiten uns diese Methode sonst noch eröffnet. Die Beispiele wurden mit fontastiq.js erstellt, einer Javascript Library für Schriftmanipulation mittels Canvas an der ich zurzeit arbeite und die Ihr auf Github Forken könnt sobald ich die gröbsten Kinderkrankheiten entfernt habe.

Selbstverständlich muss man sich nicht nur mit den Standardfunktionen der Canvas zufrieden geben. Schließlich gibt es mittlerweile eine große Zahl an Javascript Libraries zur Grafikmanipulation wie z.B.: Pixastic, paintbrush.js, Caman.js oder Bitmapdata.js, mit denen sich aufregende Effekte erzielen lassen. Ich hoffe jedenfalls, dass dieser kurze Artikel Euch einige Anregungen geben konnte um weitere ausgefallene typografische Effekte zu schaffen.


Gastautor Dirk Weber (eleqtriq) ist Interfacedesigner und Webentwickler im schönen Hilden bei Düsseldorf. Dirk schreibt in seinem Blog www.eleqtriq.com/de/ über Webstandards, UX und Flash. Eines seiner Projekte ist CSS3Warp ein Text-to-Path Generator. Dirk twittert zudem aktiv über seine Projekte.


Demo

Welche Möglichkeiten sich daraus ergeben, wird in der Canvas-Demo deutlich.

4 thoughts on “Fortgeschrittene Webtypografie mit Canvas und CSS – CSS3 Adventskalender Tag 21”

  1. Wie ist es denn mit Accessibility von solchen Javascript-erzeugten Canvas Texten? Und mit Abwärtskompaibilität?
    Ich denke, auch das trägt dazu bei, dass diese Methode noch wenig Beachtung bekommt.

  2. Man kann zwischen öffnendem und schließendem Canvas-Tag Ersatzinhalt notieren. Im Endeffekt ist Canvas nichts anderes als ein normales Bild-Element, auch in Hinblick auf Accessibility.

  3. @Anselm, diese Methode generiert, wie im Artikel beschrieben, ein Bild, das Data URI encoded als Hintergrundbild an ein Element gehängt wird. Nutzer älterer Browser oder ohne Javascript sehen dann halt den ursprünglichen HTML-Text. Deswegen ist Accessibility und Degradation kein Prob, alle Browser bis hinunter zu Mosaic 1.0 werden unterstützt :)

    @peter: stimmt, ist aber in diesem Fall nicht notwendig. Schließlich ist die Canvas hier nur ein Vehikel um besagtes Bitmap zu erzeugen und taucht garnicht erst im DOM auf.

Kommentare sind geschlossen.