Mit diesem Beitrag beginnt ein dreiteiliger Workshop mit Beispielen, um unterschiedliche Techniken für horizontale Lauftexte vorzustellen. Sie lernen, mit Vanilla JavaScript einen beliebigen RSS-Feed laden, Informationen extrahieren und damit die Inhalte ihrer Lauftexte automatisch aktuell halten.
In diesem Artikel geht es um Laufschriften mit reinen CSS-Techniken, im nächsten Beitrag nutzen wir das HTML-Element Canvas. Im letzten Teil über Laufschriften lernen Sie noch zwei nicht mehr gebräuchliche Methoden kennen und wir vergleichen die vorgestellten Techniken mit Vor- und Nachteilen. Sie benötigen zum Verständnis einige grundlegende Kenntnisse in HTML, CSS und JavaScript.
Was sind Laufschriften?
Laufschriften, im Fernsehen auch Kriechtexte genannt, sind im Digital Signage-Alltag häufig nachgefragte Funktionalitäten. Sie werden auf einem Werbemonitor mit Multizonen-Setup oftmals am unteren Rand animiert.
Was ist eine CSS Laufschrift?
Als CSS Laufschriften werden Laufschriften bezeichnet, welche mit @keyframes-Regeln aus den Cascading Stylesheets (CSS) ab Level 3 umgesetzt werden. Sie werden in Desktop-Webbrowsern sowie in WebViews von Mobilsystemen eingesetzt.
CSS Level 3
Cascading Stylesheets stellen eine Design- und Formatierungssprache für Webseiten dar. Damit lassen sich zentrale Formatvorlagen, sogenannte Stylesheets erstellen, um die Gestaltung von den Inhalten zu trennen. CSS Level 3 ist der Nachfolger des aktuellen Standards Level 2. Obwohl seit 2000 daran entwickelt wird, ist Level 3 noch nicht vollständig verabschiedet (April 2018) und es existieren nur für einige Bereiche Empfehlungen. Trotz dessen unterstützen aktuelle Browser viele CSS3 Module. Das lässt sich auf die rasante Entwicklung im Mobilbereich zurückführen, die immer wieder neue Funktionalitäten einfordert.
CSS3 bringt neben Modularisierung, Namespaces, Grafikfilter und Media Queries, die in dieser Anleitung relevante Transformationen für Animationen mit der @keyframes-Regel. Für Digital Signage Anwendungen bietet CSS3 viele Vorteile. Es lassen sich nun Animationen für Webseiten und Digital Signage Widgets umsetzen, ohne eine zusätzliche Programmiersprache wie Javascript zu bemühen. Durch Media Queries ist es außerdem leichter geworden, Webseiten oder HTML-Templates für verschiedene Ausgabegeräte mit unterschiedlichen Auflösungen oder Orientierungen gleichzeitig zu erstellen.
Reines CSS
Die Laufschrift in dieser Anleitung besteht aus reinem CSS (Pure CSS) und benötigt kein JavaScript, um zu „laufen“. Eine Digital Signage automatisiert das in der Regel und benötigt deshalb Daten. Diese kommen bei uns häufig aus einem RSS-Feed. Diesen aufzuarbeiten, geht nur mit einer Programmiersprache. In diesem Fall bietet sich das clientseitige JavaScript an.
Der erste Schritt
Aber lassen Sie uns zunächst die Struktur der Webseite aufbauen, um die Basis für CSS3-Lauftexte zu legen.
Der HTML-Teil ist übersichtlich. Im body-Bereich verschachteln wir zwei divs. Das div mit der id=“ticker“ beschreibt den zu animierenden Bereich. Der Übersichtlichkeit halber, setzen wir das den Ticker umgebenden Wrapper-div auf eine Breite von 500 Pixel mit einem 1 Pixel-Rand. Überlanger Text wird dank overflow:hidden nach 500px nicht mehr angezeigt. Der Tickerinhalt wird aus einem 30px großem Arial Font mit dem „Lorem ipsum dolor sit amet, consetetur“-Text bestehen.
Ein padding: 5px 0 im CSS sorgt dafür, dass oberhalb und unterhalb des Textes 5 Pixel Abstand zum Rand bestehen.
Die Positionseigenschaft wird auf relativ eingestellt, um die animierten Transformationen relativ zum Elternelement steuern zu können. Damit im Ticker-div auf keinen Fall der Text umgebrochen wird, muss die Eigenschaft white-space auf nowrap stehen.
Klicken Sie auf css3_animations_1.html, um das Ergebnis zu sehen.
Was sind keyframes?
Keyframes (Schlüsselbilder) beschreiben eine Animationstechnik, die ursprünglich aus Zeichentrickfilmen stammt. Dort geben Schlüsselbilder, manchmal auch Wegpunkte genannt, den Bewegungsablauf grob vor und werden im weiteren Arbeitsverlauf durch Zwischenbilder vervollständigt. In CSS können Animationssequenzen ebenfalls durch Wegpunkte festgelegt werden. Das können Positions- bzw. Größenangaben oder gar Farbwerte sein. Um einen klassischen horizontalen Lauftext zu erstellen, benötigen wir allerdings nur Positionsänderungen im CSS Stylesheet.
Animation mit der Keyframe-Regel
Eine CSS-Animation basiert auf @keyframe-Regeln. Früher musste sogenannte Browserpräfixe wie -moz- -webkit- oder -ie- genutzt werden. Inzwischen unterstützen alle aktuellen Browser Keyframes standardmäßig. Fügen wir also unter dem Style #ticker folgendes hinzu.
@keyframes moveTicker
{
from
{
transform: translate3d(100%, 0%, 0px)
}
to
{
transform: translate3d(-100%, 0%, 0px);
}
}
Mit @keyframes wird die Regel namens moveTicker eingeleitet. Hier werden zwei Schlüsselbilder eingefügt. Der erste Zustand (from) und der letzte Zustand (to). Im ersten Keyframe der Animation wird der Wert x-Eigenschaft des Textes mithilfe von translate3d auf 100% geschoben. D.h. der Text beginnt jetzt für uns unsichtbar auf der rechten Seite des Wrapper-divs. Eine Erklärung, warum wir ausgerechnet translate3d benutzen steht weiter unten. Das letzte Schlüsselbild soll der Wert der x-Eigenschaft auf -100% left stehen. D. h. der Text befindet sich wiederum unsichtbar komplett auf der linken Seite des Wrapper-divs.
Um die Animation zu aktivieren, muss im CSS des Tickers noch ein
#ticker
{
...
animation: moveTicker 10s linear infinite;
}
eingesetzt werden.
Wenn die Animation (moveTicker) startet, scrollt der Text innerhalb von 10s mit gleichbleibender Geschwindigkeit (linear) bis zur linken Seite des Wrapper-divs. Sobald der letzte Buchstabe aus dem Bild gelaufen ist (-100%) beginnt die Animation von vorn (infinite).
Glückwunsch! Sie haben Ihre erste Laufschrift animiert.
Vielleicht werden sich jetzt einige die Frage stellen, warum wir transform mit obendrein translate3d benutzen. CSS3-Lauftexte würden nämlich sowohl mit:
@keyframes moveTicker
{
from
{
left:100%;
}
to
{
left:-100%;
}
}
als auch mit
@keyframes moveTicker
{
from
{
transform: translateX(100%);
}
to
{
transform: translateX(-100%);
}
}
funktionieren.
Alle drei CSS-Varianten sind vollkommen korrekt, können sich aber unterschiedlich in der Performance auswirken. Die schlechte Nachricht ist: Sie müssen selbst herausfinden, welche Keyframe-Variante sich für Sie am besten eignet. Lange Zeit galten Transformationen generell als performanter zu Positionsänderungen mit left/top.
Allerdings trifft das inzwischen nicht mehr grundsätzlich zu. Hier
wurde festgestellt, dass unter bestimmten Voraussetzungen left/top doch mehr Effizienz bietet. Letztlich hilft nur ausprobieren. Im Beispiel mit dem RSS-Feed werden wir sehen, dass es sogar sinnvoll sein kann left und transform für CSS3-Lauftexte zu kombinieren.
Der 3D-Beschleunigungs-Trick
Die von uns gewählte Variante mit translate3d im CSS Style zwingt den Browser bzw. die WebView dazu, die sogenannte GPU-Beschleunigung für WebGL zu aktivieren. WebGL ist die standardisierte 3D-Schnittstelle für Webbrowser. Das bedeutet, dass die Berechnungen nicht auf der CPU, sondern auf dem Grafikprozessor erfolgen. Natürlich nur, sofern auch ein entsprechendes Gerät mit funktionierenden Treibern integriert ist.
Der Trick mit der GPU-Beschleunigung führt im Idealfall zu einem weicheren Scrolling mit weniger Systemlast. Leider ist dies nicht garantiert, von Hardware zu Hardware unterschiedlich und die Software muss auch mitspielen. Z.B. unterstützt die WebView eines Android bis Version 4.x gar keine 3D-Beschleunigung, selbst wenn der Chip dazu in der Lage wäre. WebGL-Beschleunigung gibt es erst ab Android 5 standardmäßig. Mit diesem Skript können Sie testen, ob für ihre Digital Signage Hardware-Softwarekombination translate3d oder translateX performanter ist.
Einen kleinen Nachteil gibt es allerdings: translate3d versteht auf seiner z-Achse keine Prozentwerte. Das ist für unsere Lauftextanwendung glücklicherweise irrelevant, da wir nur die x-Achse bewegen wollen. Somit muss der letzte Wert auf 0px stehen.
Testen Sie
Generell sollte alle aktuellen PC-Webbrowser CSS3-Animationen in Digital Signage Hardware beschleunigen. Die Unterschiede sind bei Chromium auf Linux zumindest marginal. Wir haben uns dieses Themas trotzdem so ausführlich angenommen, weil auf Digital Signage Playern nicht immer die aktuellsten Betriebssysteme eingesetzt werden. Viele günstige Medienabspieler werden mit älteren Android-Versionen ausgeliefert.
Einen Player Rk3288-Chip werden sie heute vermutlich mit maximal Android 7.1.1 erwerben können. Auch die verwendete WebView kann sich unterscheiden. Insofern ist es mit dem hier vermittelten Hintergrundwissen sinnvoll, sich die Zeit zu nehmen und auszuprobieren, welche Variante am effizientesten auf Ihren Geräten arbeitet. Aus Erfahrung weiß ich, wie sensibel Kunden auf zu ruckelige Laufschriften reagieren.
Das nächste Level
Im letzten Beispiel erstellten wir einen einfachen Lauftext zur Veranschaulichung. Der Digital Signage Alltag stellt uns aber vor größere Herausforderungen. Wenn der Text aus einem RSS-Feed kommt, variiert die Textlänge und damit auch die Geschwindigkeit. Es ist auch unbekannt welche horizontale Auflösung das Endgerät besitzt.
Deshalb müssen wir das Design flexibel gestalten. Darüber hinaus bekommen wir nun ein Problem mit der Sicherheitspolitik der Webbrowser. Die sogenannte SOP (Same-Origin-Policy) erlaubt es nicht, per Javascript oder CSS Inhalte von einer anderen Domain als die gerade eigene aufzurufen. Diese Hürden werden wir eine nach der anderen nehmen.
Eine detailliertere Erklärung zu Feed-Formaten wie RSS und Atom finden Sie übrigens im Artikel über Kanäle mit SVG und Feeds
Ein flexibleres Design
Erinnern wir uns an css3_animations_2.html. Die CSS3-Lauftexte mit RSS-Feeds sollen jetzt über die komplette Breite der Seite gehen. Wir verändern nun den Bereich des CSS Styles zu folgendem:
Ein Wrapper-div ist jetzt unnötig und wurde entfernt. Da das Ticker-div seinen Text aus dem späteren Javascript bekommt, bleibt es zunächst leer. Das onload-Ereignis im body-Tag erklären wir weiter unten.
In dem Stylesheet für den Ticker gibt es ein paar Änderungen. Die Animationsdauer wird später in Abhängigkeit von der Anzahl der Überschriften gesetzt und ist hier irrelevant.
Wie eingangs erwähnt, wissen wir nicht, welche horizontale Auflösung das zukünftige Anzeigegerät hat. Ohne die neuen Änderungen im CSS würde das Ticker-div auf die Breite des Browserfenster gesetzt werden. Diese ist in der Regel viel kleiner als die Breite des eigentlichen Textes. D. h. der Lauftext läuft nie komplett durch, weil er mittendrin immer wieder auf den Startpunkt zurückspringt und von Neuem anfängt.
Damit der Startpunkt-Reset nicht zwischendurch passiert, wird die display-Eigenschaft im Style des Elements als inline-block gesetzt. Somit können zwar horizontale Positionierungen genutzt (analog display:block) werden, aber das Element verhält sich wie ein span-Element. Diese haben keinen Zeilensprung, keine festlegbare Breite und können daher mit anderen Inline-Elementen in der gleichen Zeile stehen. Das ist wichtig, damit der Trick mit der Kombination einer Positionsangabe (left) und der Transformation (translate3d) funktionieren kann.
Positions-Transformationen
Positionsangaben und Transformationen verhalten sich unterschiedlich. Die Angabe „left“ bezieht sich auf das Elternelement, „translate“ aber auf das Element selbst.
Bei den von uns benötigten Prozentangaben fällt das besonders ins Gewicht.
Ein Beispiel: Wenn wir bei from-Bereich ein scheinbar zu „left:100%“ identisches transform: translate3d(100%, 0%, 0px) setzen würden, startet der Text viel zu weit rechts im Off. Bei jedem „herauslaufen“ links dauert es lange, bis der Text rechts wieder beginnt. Die 100% des Tickerelement sind absolut (in Pixel) gesehen größer als die 100% des Browserfensters. Durch left:100% und translate3d(0%, 0%, 0px) in den Style-Eigenschaften stellen wir sicher, dass der Startpunkt genau auf Position 100% der Browserfensterbreite steht.
Das reicht aber noch nicht aus. Der Text läuft jetzt im Browser nämlich wie oben beschrieben nicht komplett durch, sondern startet zu früh wieder von vorn. Wir müssen also zusätzlich die Werte der Endposition explizit als left:0% mit -100% transformation deklarieren, um einen kompletten Durchgang zu gewährleisten.
Welche Vorteile bieten CSS-Laufschriften?
CSS Laufschriften benötigen kein JavaScript. Sie können deshalb barrierefrei eingesetzt werden. Das Styling der Schrift (Farbe, Schatten, Laufweite usw.) erfordert keine Programmierkenntnisse. Deshalb sind auch Nicht-Programmierer wie Designer in der Lage, das einfach umzusetzen.
Der JavaScript-Teil: Ereignisse im Body
Wir haben bis jetzt eine Laufschrift mit reinem CSS erstellt. Als nächsten bauen wir JavaScript-Funktionen ein, um die Überschriften einen RSS-Feed auszulesen und als Text zusammenzustellen.
Um die Verarbeitung des Javascripts erst zu starten, nachdem der HTML-Teil komplett geladen ist, nutzen wir im body-Tag das Ereignis onLoad. Dieses Ereignis ruft die Funktion start() auf, welche einen Prozess in Gang setzt, den wir im Folgenden genauer beschreiben werden.
Der Algorithmus
Wir konstruieren einen simplen Algorithmus, der aus vier Schritten besteht.
Schritt: Das RSS als JSON-Text abholen
Schritt: Das erhaltene JSON in ein Javascript-Objekt konvertieren
Schritt: Aus dem Javascript-Objekt den Text für den Ticker extrahieren
Schritt: Den Tickertext ausgeben
JSON (JavaScript Object Notation) ist übrigens ein Standardformat in Textform, um strukturierte Daten unkompliziert austauschen zu können. Es ist zwar schlechter lesbar als das XML-Format, besitzt aber dafür weniger Overhead. Außerdem kann Javascript JSON effizient in Objekte umwandeln.
Der SOP Bypass
JavaScript oder Daten von anderen Domains (Origins) nachzuladen, stellt einen kritischen Angriffsvektor dar. Der andere Server könnte beispielsweise gehackt sein. Wenn andere Server und Webbrowser darauf zugreifen, kann ein Angreifer alle Nutzer gewissermaßen huckepack mit dem Nachladen von Schadcode kompromittieren. Die SOP soll das verhindern. In unserem Szenario steht sie aber leider weitestgehend im Weg.
SOP austricksen
Für die Beispiele benutzen wir unseren eigenen RSS-Feed auf https://smil-control.com/de/magazin/feed/. Um diesen abzufragen, ohne mit dem oben erwähnten Sicherheitskonzept des Browsers in Konflikt zu geraten, gibt es Lösungen wie CORS (Cross-Origin Resource Sharing),
JSONP oder gar ein eigenes serverseitiges Skript.
Allerdings besitzen diese Lösungen ihre Vor- und Nachteile und erfordern Zusatzarbeiten, deren Erläuterungen den Rahmen dieses Kurses sprengen würden.
Ich habe deshalb ein kleines Skript geschrieben und unter GitHub veröffentlicht. Das Skript ist weitestgehend zur eingestellten Yahoo-Api kompatibel. Daher lässt sich mit diesem Tutorial einsetzen. Das ist immer noch komfortabler als JSONP oder CORS.
1. Schritt: RSS als JSON-Text abholen
Beginnen wir mit unserem Algorithmus. Die Funktion getRSS wird mit der Url des RSS-Feeds aufgerufen und sieht so aus:
function getRSS(url)
{
var request_url = 'https://smil-control.de/beispiele/fetch-rss.php?feed_url='+url;
var MyRequest = new XMLHttpRequest();
MyRequest.open("GET", request_url, true);
MyRequest.onload = function (e)
{
if (MyRequest.readyState === 4)
{
if (MyRequest.status === 200)
{
handleTicker(MyRequest.responseText);
}
else
{
console.error(MyRequest.statusText);
}
}
};
MyRequest.onerror = function (e)
{
console.error(MyRequest.statusText);
};
MyRequest.send(null);
}
Als Erstes wird die Abfrage-Url zusammengestellt. Da für die Laufleiste nur der Title als Überschrift relevant ist, fordern wir auch nur den an. Mit new XMLHttpRequest() wird ein neues Objekt (hier: MyRequest) für eine Datenabfrage über eine Url angelegt. Durch die Funktion open() wird eine GET-Afrage asynchron initialisiert und schließlich mit send() abgeschickt. GET stellt eine einfache HTTP-Anfrage dar, um Daten von einem Server anzufordern. Im Prinzip als ob Sie etwas in die Adresszeile Ihres Browsers eingeben.
Was bedeutet Asynchron?
Asynchron bedeutet, dass nach dem Senden der Abfrage das Skript nicht auf die Antwort wartet, um fortzufahren. Das sind die in modernen Webanwendungen üblichen sogenannten AJAX-Abfragen. Asynchrone Datenabfragen werden im Hintergrund ausgeführt und blockieren der Browser nicht. Der kann dann mit anderen Dingen fortfahren, wie dem Bildaufbau.
JavaScript Ereignisse
Des Weiteren erstellen wir zwei sogenannte Eventhandler-Funktionen für das XMLHttpRequest-Objekt. Onerror wird aktiviert, wenn es einen Fehler gibt, z. B. das Skript nicht erreichbar ist. Sollte der Fall eintreten, schreiben wir die Fehlermeldung in die Konsole. In der Funktion onload wird geprüft, ob ein Ergebnis vorliegt. Die readyState-Eigenschaft der Abfrage nimmt hierbei den Wert 4 ein.
Als Nächstes wird der sogenannte Statuscode der Antwort des Skripts überprüft. Wenn alles in Ordnung ist, steht der Statuscode auf 200 und das Skript übergibt den Text der Antwort an die Funktion handleTicker() zum Weiterverarbeiten. Andernfalls wird eine Fehlermeldung in der Konsole ausgegeben.
Webserver-Abfragen und Antworten
Webserver verschicken standardmäßig auf eine sogenannte Query (Anfrage) eine Response (Antwort) mit einem numerischen Statuscode. Im Erfolgsfall ist das die 200. Fehler beginnen mit einer 4 oder 5. Sie haben sicherlich schon mal eine Seite aufgerufen, die nicht vorhanden war. Das Browserfenster zeigt dann die „berühmte“ Fehlermeldung 404 an.
Für Programmierer ist das praktisch. So prüfen wir, ob der Server korrekt antwortet.
Die Funktion handleEvent übernimmt nun im Erfolgsfall die weiteren Schritte des oben ermittelten Algorithmus.
function handleTicker(response)
{
var feed_obj = JSON.parse(response);
var ticker_text = createTickerOutput(feed_obj);
displayTicker(ticker_text, feed_obj.query.count);
}
2. Schritt: JSON zu Objekt konvertieren
Der aus der Funktion getRSS() übergebenen Text im JSON-Format wird mit JSON.parse(response) in ein Javascript-Objekt umgewandelt.
Achtung! In alten Tutorials ist eventuell von eval() die Rede, da JSON.parse erst Dezember 2009 als ECMA 5.1 Standard eingeführt wurde. Mit eval() lassen sich nicht nur JSON in Objekte umwandeln, sondern auch Javascript-Code ausführen.
Versuchen Sie die Nutzung grundsätzlich zu vermeiden, weil diese auch das Risiko birgt, ungewollt eingeschleusten Schadcode zur Ausführung zu bringen. JSON.parse() ist sicherer und wird zudem schneller ausgeführt.
Ich hoffe, dass es nur eine Frage der Zeit ist, bis die eval()-Funktion komplett aus der ECMA-Standardisierung rausfliegt. Immerhin ist das mit einer der Hauptgründe für den schlechten Ruf von Javascript.
3. Schritt: Extrahieren des Ticker-Textes
function createTickerOutput(feed_obj)
{
var ticker_text = "";
for (var i = 0; i < feed_obj.query.count; i++)
{
ticker_text += feed_obj.query.results.item[i].title+ " +++ ";
}
return ticker_text;
}
Die Funktion durchläuft mit der for-Schleife Schritt für Schritt alle Meldungen (items) des Feed-Objektes. Dabei wird das title-Feld für die Schlagzeile extrahiert und dem String ticker_text angefügt. In ticker_text befinden sich nach Beendigung der Schleife alle Schlagzeilen mit einem „+++“ getrennt. Diese Variable wird zurückgeliefert und bildet die Basis für den Lauftext.
Die Animationsdauer ermitteln
Die Geschwindigkeit, mit der eine Animation in der Schleife abläuft, muss im Stylesheet gesetzt werden. Eine feste Zeit birgt Probleme bei unterschiedlichen Textlängen. In 10s lassen sich 20 Überschriften, die ein Feed haben kann, sicherlich nicht bequem lesen. Ist die Zeit hingegen zu hoch, wird die Geschwindigkeit des Lauftextes zu niedrig und der Ticker scrollt quälend langsam. Abhilfe schafft eine Funktionalität, die in Abhängigkeit zu der Anzahl der Überschriften die Animationsdauer ermittelt:
function getAnimDurationInSeconds(num)
{
var seconds = num*10;
return seconds.toString()+"s";
}
Um die Animationsdauer zu berechnen, setzen wir 10s Lesezeit pro Schlagzeile an. Bei fünf Schlagzeilen wären das 50 Sekunden. Gute Schlagzeilen bestehen in der Regel aus 4–8 Wörtern. Also sollten 10 Sekunden Zeit einen ruhigen Lauftext zu lesen näherungsweise angemessen sein. Sie können aber auch gerne mit diesem Faktor „herumspielen“, bis die Geschwindigkeit Ihren Wünschen entspricht.
4. Schritt: Der Lohn der Mühen
Im letzten Schritt befüllen wir das Ticker-div mit dem oben extrahiertem Text und setzen die Animationszeit in Sekunden.
function displayTicker(ticker_text, num_headlines)
{
var ticker = document.getElementById("ticker");
ticker.innerHTML = ticker_text;
ticker.style.animationDuration = getAnimDurationInSeconds(num_headlines);
}
Wir initialisieren erst eine Variable namens ticker, um das Ticker-div anzusprechen. Als Nächstes bekommt das div den Tickertext mit den Schlagzeilen und zum Schluss setzen wir im CSS die berechnete Animationszeit.
Klicken Sie auf
css_animation_rss.html, um die CSS3-Lauftexte mit RSS zu betrachten. Sie werden sehen, dass der Ticker sich immer gleich verhält. Sogar wenn Sie während des Ablaufes die Breite Ihres
Browserfensters ändern.
Zum nächsten Teil
Im nächsten Beitrag geht es um HTML Laufschriften. Wir werden den gleichen Lauftext in einem HTML5-Canvas erstellen und diesen ebenfalls mit Inhalten aus einem RSS-Feed befüllen.
Bei Fragen oder Anmerkungen zu CSS-Animationen oder Laufleisten haben, können Sie mich gerne kontaktieren.