Gunther: Application Cache - Fonts (Formate)

Hallo werte Selfgemeinde,

ich überlege aktuell, wie man folgendes "Problem" am geschicktesten löst/ lösen kann:
Wenn ich den Application Cache für meine Website nutzen möchte, dann muss ich ja alle externen Resourcen, die gespeichert werden sollen, explizit in der Manifest-Datei angeben.

Aber wie mache ich das denn bei Fonts?
Bei der "klassischen" Einbindung per CSS ist jeder Browser ja so schlau, und lädt aus den "angebotenen" Formaten nur das, welches er favorisiert.

Heutzutage verstehen ja die allermeisten Browser das WOFF Format, aber halt nicht alle.

Und wenn ich jetzt alle Font Formate mal X Schriften im Manifest angebe, dann erhöht sich das Volumen recht kräftig.

Gibt es dafür eine "elegante" Lösung, und wenn ja, wie sieht die aus?

Besten Dank im Voraus!

Gruß Gunther

  1. Hallo,

    Gibt es dafür eine "elegante" Lösung

    Nicht dass ich wüsste. Gedanklich habe ich einige durchgespielt, aber elegant waren die nicht. ;) Oder sie sind Caching-Lösungen zusätzlich zum Manifest, über die man mit JavaScript bessere Kontrolle hat.

    Ich sehe Manifest-Caching auch eher in dem Anwendungsbereich, wo ich nicht viele Assets cache, sondern nur die nötigen. Wenn du zahlreiche Fontdateien hast, würde ich anfangen da zu optimieren. Im Zweifelsfall auf eigene Fonts verzichten.

    Siehe auch
    http://alistapart.com/article/application-cache-is-a-douchebag#section13
    http://stackoverflow.com/questions/17664717/most-efficient-webfont-configuration-with-html5-appcache

    Dass die Application-Cache-Spezifikation schrecklich ist, ist bekannt, leider gibt es noch keine wirkliche Alternative.

    Mathias

    1. @@molily:

      nuqneH

      Siehe auch
      http://alistapart.com/article/application-cache-is-a-douchebag#section13

      Siehe auch
      https://twitter.com/g16n/status/247716954306138113 ;-)

      Qapla'

      --
      „Talente finden Lösungen, Genies entdecken Probleme.“ (Hans Krailsheimer)
    2. Hallo Mathias!

      Gibt es dafür eine "elegante" Lösung

      Nicht dass ich wüsste. Gedanklich habe ich einige durchgespielt, aber elegant waren die nicht. ;) Oder sie sind Caching-Lösungen zusätzlich zum Manifest, über die man mit JavaScript bessere Kontrolle hat.

      Das hatte ich befürchtet ...!

      Ich sehe Manifest-Caching auch eher in dem Anwendungsbereich, wo ich nicht viele Assets cache, sondern nur die nötigen. Wenn du zahlreiche Fontdateien hast, würde ich anfangen da zu optimieren. Im Zweifelsfall auf eigene Fonts verzichten.

      Nur sehr ungern ... ;-)

      Siehe auch
      http://alistapart.com/article/application-cache-is-a-douchebag#section13
      http://stackoverflow.com/questions/17664717/most-efficient-webfont-configuration-with-html5-appcache

      Danke - kenne ich schon ...

      Dass die Application-Cache-Spezifikation schrecklich ist, ist bekannt, leider gibt es noch keine wirkliche Alternative.

      Auch auf die Gefahr hin, dass ich mich wiederhole, aber ...
      Das eigentliche Problem besteht (mal wieder) darin, dass man serverseitig nicht die nötigen Infos hat, um bspw. das Manifest entsprechend on-the-fly zusammenzustellen.

      Ein entsprechender Header wie z.B. der Accept-Language Header für die Fonts würde ja Abhilfe schaffen. Genauso bei etlichen anderen "Problemen" wie bspw. bei den Images.

      Soweit ich das richtig verstanden habe, lädt der Browser "alle" Resourcen einer Seite aus dem Application Cache, sofern einer für die entsprechende Seite vorhanden/ angegeben ist.

      Wie sieht das denn dann aus, wenn man im Manifest in der Network Sektion einen '*' einträgt, was dem Browser ja erlaubt, alle fehlenden Resourcen über das Netz nachzuladen. Holt er dann diese Resourcen nicht ggf. aus seinem "normalen" Cache?

      Im Moment erscheint mir eine Variante, die Local Storage verwendet da fast besser geeignet zu sein, als der Apllication Cache. Denn dieser besitzt imho zu viele Nachteile, bzw. Unzulänglichkeiten.

      Gruß Gunther

      1. Das eigentliche Problem besteht (mal wieder) darin, dass man serverseitig nicht die nötigen Infos hat, um bspw. das Manifest entsprechend on-the-fly zusammenzustellen.

        Das Grundproblem ist vielmehr, dass ein deklaratives Manifest den Ansprüchen heutiger Webapps nicht genügt. Sie laden Daten gemäß einer komplexen Logik, die sich nicht so einfach deklarativ ausdrücken lässt. Ich denke nicht, dass man dem mit Headern beikommen kann. Dieses Modell skaliert nicht. Wie sollte man irgendwelche JavaScript-Fähigkeiten, die ein Polyfill benötigen oder nicht, in einem Header ausdrücken? Das kann nur in JavaScript geschehen.

        Soweit ich das richtig verstanden habe, lädt der Browser "alle" Resourcen einer Seite aus dem Application Cache, sofern einer für die entsprechende Seite vorhanden/ angegeben ist.

        Ja, allerdings im Hintergrund, soweit ich weiß, also die Seite lädt dadurch nicht unbedingt langsamer. Unschön ist die Datenmenge trotzdem.

        Wie sieht das denn dann aus, wenn man im Manifest in der Network Sektion einen '*' einträgt, was dem Browser ja erlaubt, alle fehlenden Resourcen über das Netz nachzuladen. Holt er dann diese Resourcen nicht ggf. aus seinem "normalen" Cache?

        Ja, soweit ich weiß. Das Manifest setzt den normalen Cache nicht außer Kraft. NETWORK heißt nicht, dass ein Request erzwungen wird, er kann auch aus dem Cache bedient werden.

        Im Moment erscheint mir eine Variante, die Local Storage verwendet da fast besser geeignet zu sein, als der Apllication Cache. Denn dieser besitzt imho zu viele Nachteile, bzw. Unzulänglichkeiten.

        Das ist glaube ich Konsens. ;)

        Wobei localStorage und IndexedDB noch keinen Sync-Mechanismus und kein Asset-Management mitbringen. Die müsste man selbst entwickeln. PouchDB geht in eine solche Richtung, wobei es weniger für Assets gedacht ist.

        Mathias

        1. Das eigentliche Problem besteht (mal wieder) darin, dass man serverseitig nicht die nötigen Infos hat, um bspw. das Manifest entsprechend on-the-fly zusammenzustellen.

          Das Grundproblem ist vielmehr, dass ein deklaratives Manifest den Ansprüchen heutiger Webapps nicht genügt. Sie laden Daten gemäß einer komplexen Logik, die sich nicht so einfach deklarativ ausdrücken lässt.

          ACK.
          Es wäre demnach wesentlich hilfreicher und effizienter, wenn man das Anlegen eines Manifests dem Browser überlassen würde. Also ihm quasi sagen könnte, packe alle Resourcen dieser Seite (mit Ausnahme von 'xyz') in den Application Cache und erzeuge eine entsprechende Manifest-Datei.

          Ich denke nicht, dass man dem mit Headern beikommen kann. Dieses Modell skaliert nicht. Wie sollte man irgendwelche JavaScript-Fähigkeiten, die ein Polyfill benötigen oder nicht, in einem Header ausdrücken? Das kann nur in JavaScript geschehen.

          Wieso sollte dieses Modell denn "skalieren" können!?
          Die Fähigkeiten eines Browsers skalieren doch auch nicht, und nur darauf kommt es an.

          Beispiel (Schriftarten):
          X-Fonts:woff=0.8,ttf=0.5,svg=0.3

          Beispiel (Pixelratio):
          X-Pixel-Ratio: 2

          Alleine mit diesen Infos auf der Serverseite ließen sich viele Dinge ganz einfach lösen, für die man heutzutage entweder Javascript braucht, sie dem Browser überlassen muss (der sich bspw. aus mehreren Alternativen seine Bevorzugte selbst raussucht) oder mit einem Fallback leben muss!

          Alternativ sind wir ansonsten wieder beim UA-Sniffing

          Im Moment erscheint mir eine Variante, die Local Storage verwendet da fast besser geeignet zu sein, als der Apllication Cache. Denn dieser besitzt imho zu viele Nachteile, bzw. Unzulänglichkeiten.

          Das ist glaube ich Konsens. ;)

          Na immerhin - ist ja schön, wenn es auch mal einen Konsens gibt ...! ;-)

          Wobei localStorage und IndexedDB noch keinen Sync-Mechanismus und kein Asset-Management mitbringen. Die müsste man selbst entwickeln. PouchDB geht in eine solche Richtung, wobei es weniger für Assets gedacht ist.

          Hmmm ..., also wäre aktuell ggf. ein "Mix" aus Application Cache, Local Storage und Browser Cache die "beste" Variante ...!?

          Um auf meine eigentliche Ausgangsfrage zurückzukommen:
          Wie wir festgestellt haben, sind Fonts denkbar "ungeeignet", um sie im Application Cache zu speichern (da man alle Formate speichern müsste, weil es keine Möglichkeit gibt, vorher festzustellen, welches Format der jeweilige Browser unterstützt).

          Aber eine oder mehrere fehlende Fonts-Files hindern den Browser ja nicht daran, eine Seite trotzdem anzuzeigen. Also könnte man z.B. auch hingehen und sagen:"OK, fast alle Browser, die Application Cache unterstützen, verstehen auch das WOFF Format (mit Ausnahme vom Android Browser < 4.4)! Also packe ich entweder nur die WOFF Files in mein Manifest, oder zusätzlich auch noch die TTF Files (für besagte Android Browser), oder ich versuche das serverseitig per UA-Sniffing zu ermitteln (was bei der Mobile Version noch relativ einfach & zuverlässig möglich ist)."

          Wirklich "schön", bzw. praktisch & zweckmäßig ist das aber alles nicht ...! :-(

          Gruß Gunther

          1. Wieso sollte dieses Modell denn "skalieren" können!?

            Man kann nicht für jedes Browserfeature, das für den Server relevant sein könnte, einen Header senden. Das wären hunderte.

            Aber eine oder mehrere fehlende Fonts-Files hindern den Browser ja nicht daran, eine Seite trotzdem anzuzeigen.

            Ja, das sollte man natürlich testen. Oftmals wird gar kein Text angezeigt, während Fonts geladen werden. Wenn man Fonts unter NETWORK packt aber die Verbindung schlecht ist, kann es sein, dass erst nach 15s ein Request-Timeout passiert. Der Browser sollte hier nicht auf den Font warten.

            Lässt man sie aus NETWORK heraus, sollte der Browser sofort merken, dass die Ressource nicht verfügbar ist, und den systemeigenen Fallback-Font benutzen. Hoffe ich mal. ;)

            Also könnte man z.B. auch hingehen und sagen:"OK, fast alle Browser, die Application Cache unterstützen, verstehen auch das WOFF Format (mit Ausnahme vom Android Browser < 4.4)! Also packe ich entweder nur die WOFF Files in mein Manifest

            Das klingt vernünftig. Das würde ich tun.

            Mathias

  2. Hallo werte Selfgemeinde,

    für's Archiv:
    Ich habe mich jetzt für folgende Variante entschieden:
    Per @font-face Deklaration binde ich meine benötigten Schriftarten (3 an der Zahl) in meiner (einen) CSS-Datei ein.

    Dabei verwende ich für das .woff Format einen Data-Uri, sprich ich binde die Woff-Datei inline Base64 encoded ein.

    Auf diese Art & Weise brauchen alle Browser, die das Woff-Format unterstützen, keinen zusätzlichen HTTP Request und ich kann/ könnte auch meine CSS-Datei über eine entsprechende Manifest-Datei in den Application Cache packen.

    So sieht dann der entsprechende CSS-Code aus:

    @font-face {  
    	font-family:"PT Serif";  
    	src: url("../font-files/ptserif_bold.eot");  
    	src: url("../font-files/ptserif_bold.eot?#iefix") format("embedded-opentype"),  
    	url(data:application/x-font-woff;charset=utf-8;base64,[Base64 Data]) format("woff"),  
    	url("../font-files/ptserif_bold.ttf") format("truetype"),  
    	url("../font-files/ptserif_bold.svg#PT Serif") format("svg");  
    	font-weight: 700;  
    	font-style: normal;  
    }
    

    Alle anderen Browser, also die das Woff-Format nicht unterstützen, laden sich ihre entsprechende Font-Datei dann lokal.

    Dadurch kann man zwar kein CDN mehr verwenden, aber die Browser, die das Woff-Format nicht unterstützen "sterben" über kurz oder lang eh aus!

    Und imho gleicht die Einsparung von 3 Requests (bei jedem Seitenaufruf) den Base64 Overhead mehr als aus. Natürlich wird die CSS-Datei 'gzipped' ausgeliefert.

    Aber falls jemand eine andere/ bessere Methode kennt und/ oder sonstige Nachteile dieser Variante ausgemacht hat - immer raus damit! ;-)

    Gruß Gunther