Pixelfans

Kategorie: JS

20 Dez 2011

Eine Seite für alle Fälle

geschrieben von Pawel

Es gab Zeiten, da durften Ärzte nicht für sich werben. Heute hat sogar mein Zahnarzt eine Website. Er hat mir versichert, dass ihn darüber zunehmend auch neue Patienten finden. Es gibt also anhaltend Anwendungsfälle mit relativ konstanten Inhalt. Dazu habe ich ja auch schon mal im Blog geschrieben. Hier reicht eine Seite (Onepager), die aber mit Javascript in Kleinteile "zersägt" wird, um die Inhalte ein bisschen abzusetzen und die gesamte Seite lesbarer zu gestalten.

Wenn ich die (momentane) HTML5-Spezifikation nicht völlig falsch verstanden habe, kann man jeden Inhaltszusammenhang in eine section packen. Da Javascript dafür sorgt, dass jeweils nur ein Bereich angezeigt wird, mutet es wie eine mehrseitige Präsenz an. Damit werden Ressourcen gespart, da insgesamt weniger Daten übertragen werden. Es gibt keine zusätzlichen Requests, da das CSS und Javscript im head des Dokuments stehen. Bei kleinen Dateien lohnt die Auslagerung in seperate Dateien nicht.

Diese Vorteile kommen noch mehr zur Geltung, wenn die Seite mit einem Smartphone genutzt wird. Das coole an Smartphones ist, dass sie spätestens alle 2 Jahre erneuert werden und Javascript immer läuft.

Desktoprechner werden steuerlich in 4-5 Jahren abgeschrieben und noch länger genutzt. Daher finden sich dort noch ein paar Uraltbrowser, deren Zeit aber abläuft. Netscape 4.6 ist ja auch verschwunden.

Auf mobilen Geräten kann man CSS @media-queries voraussetzen. Selbst wer unbedingt Windows Mobile benutzt und nicht reflexartig Opera Mobile installiert hat, findet nach dem Mango-Update jetzt den IE9 vor, der dies auch versteht. Für mich sind damit handheld-Angaben obsolet.

Für meinen konkreten Anwendungsfall ist es wichtiger auf den Fall zu reagieren, wann die Navigation nicht mehr ins portrait-Format passt. Seltsamerweise gibt es im Netz nicht viele Tipps, die sich mit der Navigation auf kleinen Screens auseinandersetzen. Ich habe nur ein Tutorial auf CSS-Tricks gefunden, das mir aber nicht gefiel. Ich wollte ein Menü, das ich auch noch treffe, nachdem ich meiner Mutter den Garten umgegraben habe.

Ich habe die Navigation gestaltet und brauchte nur noch einen Button, um die Navigation sichtbar bzw. unsichtbar zu machen. Der Button sollte gut sichtbar und erreichbar sein. Die zunächst naheliegende Variante, den button mit Pseudoelementen zu kreeiren habe ich wieder verworfen. Einerseits ist ein solcher Button im Firefox Mobile schwer bedienbar und andererseits fällt sofort auf, dass touch- und hover-Events sich deutlich unterscheiden. Das Mobiltelefon bemerkt natürlich nicht, dass der Finger weg ist und die Navigation bleibt solange sichtbar, bis der Finger irgendwo auf den Screen tippt. Unschön.

Bei meiner Lösung galt es sicherzustellen, dass der mit Javscript erzeugte button nur bei der Verwendung der mobilen @media-queries gezeigt wird, . Empfohlen sei hier die Angabe max-device-width. Angaben ohne -device- interpretieren manche Mobilbrowser nicht. Das Ungetüm

mobile = window.getComputedStyle($t('html')[0], null).getPropertyValue('border-top-style') === 'dashed' ? 'true' : 'false';

fragt nach einen bestimmten Stilmerkmal des html-Elements, dem ich für kleine Screens, oben eine gestrichelte Linie zugewiesen habe. Screenshot der Seite mit Windows Mobile Einige mobile Browser habe diese tatsächlich angezeigt, weswegen ich die Liniestärke auf 0 gesetzt habe. Wenn das Stilmerkmal vorhanden ist, muss also die @media-query funktionieren. Glücklicherweise beherrschen auch alle diese Browser .getComputedStyle. Es gibt neuere Smartphones, die im landscape-Modus mehr Pixel anzeigen, als die hier angesetzten 600px. Daher wird bei jedem resize-Event, also auch beim Drehen, die Funktion checkScreen() aufgerufen. Damit bei kleineren Displays nicht ständig neue Buttons entstehen, muss überprüft werden, ob er noch nicht erzeugt wurde. Mit .removeChild(button) ist er nur aus dem DOM entfernt, aber noch vorhanden. Diesen Fall galt es zu berücksichtigen. Die Mobilvariante ist jetzt fertig.

Die allgemeinen Stilregeln verhelfen auch alten IE's zu einer bedienbaren Seite. Moderne Browser zeigen mehrere Spalten sowie CSS-Muster. Letztere können erheblich Performance kosten.

Demo eines Onepagers für alle Displaygrößen

Kategorie: CSS , Ideen , JS , Layout | Kommentare (0) | Trackbacks (0) | Permalink

28 Nov 2010

Feature detection für SVG

geschrieben von Pawel

Für den letzten Blogeintrag über Twitter habe ich auf die Grafik des Vogels bei openclipart.org verlinkt. Sieht man sich diese Grafik mit Safari oder dem IE9 an, sieht sie ziemlich schlecht aus.Twitterbird without Filter Das liegt daran, dass diese Browser bisher filter überhaupt nicht interpretieren. Dadurch sparen sie erhebliche Rechenzeit, erschweren damit aber selbst einfachste grafische Effekte. Das es besser geht zeigt, wieder einmal Chrome, der schnell bleibt und in der Interpretation von filter jetzt zu Opera und Firefox aufschließt.

Für die Grafik bei openclipart.org ist das ohne Belang, da Inkscape und andere Programme selbstverständlich diese Fähigkeiten haben und langfristig (bis Ende 2011) Safari und der Internet Explorer darum nicht herum kommen. Will man die Grafik heute im Web einsetzen, kann man natürlich diese Pfade weglassen, was ich auch getan habe. Eine andere Möglichkeit ist eine Browserweiche, welcher die Pfade nur dann ausblendet, wenn die Eigenschaft vom Browser nicht unterstützt wird. (feature detection)

Es soll nicht darum gehen, bestimmte Browser über ihren UA-String zu erkennen, sondern zu testen, ob sie die gewünschten Fähigkeiten haben. Dafür scheint ein in das Dokument integriertes Script, welches .hasFeature() nutzt, wie geschaffen. Das klappt auch recht gut, um Animationen zu erkennen, wie das c't-Beispiel zeigt.

Leider funktioniert das bei der Erkennung von SVG-Filtern, bisher nur in Opera. Folgende Lösung ist durch Anregung der SVG-Developer-Liste und von Thomas Meinike entstanden:

function noFilter() {
  document.getElementById("highlight").setAttribute("opacity",0);
  document.getElementById("highlightwing").setAttribute("opacity",0)
}
function init() {
var fsupport = ((document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Filter", "1.1")) || (!!document.createElementNS && /SVGFE/.test(toString.call(document.createElementNS('http://www.w3.org/2000/svg','feGaussianBlur')))))? true : false; 
if (!fsupport) noFilter();
}
document.addEventListener("DOMContentLoaded", init, false);

Das Script wird beim Laden der Seite aufgerufen und setzt die Sichtbarkeit der "verwischten" Bereiche auf 0. Den kryptische Teil der init-Funktion, der von Erik Dahlström stammt, will ich kurz erklären:

(toString.call(document.createElementNS('http://www.w3.org/2000/svg','feGaussianBlur')))

Call ruft eine Funktion auf, die ein Objekt erstellt, die den Verwischen-Filter enthält. Das gelingt natürlich nur, wenn der Browser das auch unterstützt. Deshalb kann mit dem regulären Ausdruck

/SVGFE/

überprüft werden, ob dieser enthalten ist. Dies erledigt .test. Wenn es keine Übereinstimmung gibt, wird die Funktion noFilter() aufgerufen.

Demo des Twittervogels mit Featureerkennung

Da sich Otto Normalnutzer eine Seite nicht mit unterschiedlichen Browsern ansieht, wird die feature detection nur auf den Verwischen-Filter angewandt, um eine Störung des grafischen Effekts zu verhindern. Natürlich wird der Effekt, der die Federn simulieren soll, auch nicht angewandt.

Ergänzung (01.12.2010:)

Die Anregung von @molily habe ich aufgegriffen:

function init() {
var fsupport = ((document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Filter", "1.1")) || (typeof document.createElementNS('http://www.w3.org/2000/svg','feGaussianBlur').setStdDeviation == 'function'))? true : false; 
if (!fsupport) noFilter();

Hier liegt der Clou darin, dass das erzeugte Obkekt daraufhin überprüft wird, ob eine bestimmte Funktion existiert. Für den blur-Filter muss es eine Standardabweichung geben.

verbesserte Demo des Twittervogels

Kategorie: Ideen , JS | Trackbacks (0) | Permalink

23 Sep 2010

Workaround für den Webkitbug

geschrieben von Pawel

object ist das Containerlement für Multimediaelemente schlechthin. Es ermöglicht die Angabe von Alternativinhalten, die angezeigt werden, wenn sich der Browser auf den Medientyp nicht versteht. Häufig wird der Tag bei Flashfilmen, etwa von Youtube eingesetzt, aber er eignet sich auch hervorragend für die Einbindung von SVG, die fast jeder moderne Browser anzeigen kann. Der Internet Explorer benötigt bis einschließlich der Version 8 dafür ein Plugin. Selbst die Einbindung des SVG via data/uri ist möglich, was zusätzliche Requests spart.

Das Designerherz könnte nicht höher schlagen, wenn die Webkitbrowser, ab der Version 4 nicht einen hässlichen Bug mitbringen würden. Wenn keine Hintergrundfarbe angegeben wird, zeigen sie das eingebette Objekt in seiner ganzen Eckigkeit mit blütenweißen Hintergrund. Das ist so gut wie nie erwünscht, es sei denn ein Diagramm ist rechteckig oder die Website hat einen weißen Hintergrund.

Als Workaraund mag manchmal das bewußte Verwenden von Farben oder Biildhintergründen dienen, ich habe noch einen weiteren Vorschlag.

Der Workaround beruht darauf, dass Webkitbrowser diese Darstellungsprobleme, bei der Einbindung als img nicht haben. Der object-Tag kann also zur Laufzeit mit JavaScript umgeschrieben werden, was eigentlich recht simpel ist.

Ich hatte den Anspruch

  • kein JavaScript-Framework zu verwenden
  • das Umschreiben nur für Webkit zu veranlassen
  • nur SVG's zu erfassen, bei anderen Medieninhalten den Tag zu belassen
  • ein mehrfach verwendbares Skript zu entwickeln

Teil des JavaScripts

var i=document.createElement("img");
i.src=e.data;
if(e.firstChild.nodeType == 3){
i.alt=e.firstChild.nodeValue;}
else i.alt="Die SVG-Grafik kann nicht angezeigt werden."; 
p = e.parentNode;	
p.replaceChild(i,e);

Es wird ein neues Bildelement erzeugt und der Inhalt des data-Feldes, welches den Pfad zur SVG enthält auf das src übertragen. Es wird noch überprüft, ob der Alternativinhalt aus Text besteht, der dann Inhalt der Alternativbeschreibung des Bildes wird. Sollte der Alternativinhalt kein Text sein, wird er ersetzt. Nachdem das Skript das Elternelement ermittelt hat wird das object durch ein img ersetzt.

Wäre nur ein Tag zu ersetzen, würde diesen kurzen Anweisungen schon ausreichen. Kniffliger ist es, alle obigen Voraussetzungen umzusetzen, was ich ohne einen Programmiermuttersprachler wie Thomas Meinke nicht geschafft hätte. Die Prüfung, ob das Element SVG-Content enthält

e.type=="image/svg+xml"
scheitert innerhalb einer einfachen Schleife, da die length-Eigenschaft sich zur Laufzeit ändert. Der finale Code erfüllt alle Anforderungen:

Demo des Workarounds für Webkit

Der Workaround ist eher dort geeignet, wo SVG als Bilder verwendet werden und ist ein weiteres Argument dafür, SVG's auch heute schon einzusetzen.

Nachtrag 10.10.2010: Die aktuelle Beta vom Chrome 7 hat den Bug behoben.

Kategorie: Ideen , JS , SVG | Kommentare (0) | Trackbacks (0) | Permalink