Woher wissen Sie, ob eine Schriftart (@ font-face) bereits geladen wurde?

80

Ich verwende Font-Awesome, aber während die Schriftdateien nicht geladen sind, werden die Symbole mit  angezeigt.

Ich möchte also, dass diese Symbole angezeigt werden, display:nonewährend Dateien nicht geladen werden.

@font-face {
  font-family: "FontAwesome";
  src: url('../font/fontawesome-webfont.eot');
  src: url('../font/fontawesome-webfont.eot?#iefix') format('eot'), url('../font/fontawesome-webfont.woff') format('woff'), url('../font/fontawesome-webfont.ttf') format('truetype'), url('../font/fontawesome-webfont.svg#FontAwesome') format('svg');
  font-weight: normal;
  font-style: normal;
}

Woher weiß ich, dass diese Dateien geladen wurden und ich endlich die Symbole anzeigen kann?

Bearbeiten: Ich spreche nicht, wenn die Seite geladen wird (Onload), da die Schriftart vor der gesamten Seite geladen werden könnte.

Shankar Cabus
quelle
Hoffentlich können wir bald native Font-Ereignisse haben blog.typekit.com/2013/02/05/more-reliable-font-events
Pacerier
2
Diese Frage ist ein Duplikat und ich habe eine Antwort auf das Update 2015 für die ursprüngliche Frage veröffentlicht.
Dan Dascalescu
Es gibt eine Lösung, die Scroll-Erkennung unter smnh.me/web-font-loading-detection-without-timers verwendet
Pacerier

Antworten:

44

Jetzt auf GitHub: https://github.com/patrickmarabeas/jQuery-FontSpy.js

Im Wesentlichen vergleicht die Methode die Breite einer Zeichenfolge in zwei verschiedenen Schriftarten. Wir verwenden Comic Sans als Schriftart zum Testen, da es sich um die unterschiedlichste web-sichere Schriftart handelt und sich hoffentlich von jeder benutzerdefinierten Schriftart unterscheidet, die Sie verwenden werden. Zusätzlich verwenden wir eine sehr große Schriftgröße, sodass auch kleine Unterschiede erkennbar sind. Wenn die Breite der Comic Sans-Zeichenfolge berechnet wurde, wird die Schriftfamilie in Ihre benutzerdefinierte Schriftart geändert, wobei auf Comic Sans zurückgegriffen wird. Wenn diese Option aktiviert ist und die Breite des Zeichenfolgenelements gleich ist, wird die Fallback-Schriftart von Comic Sans weiterhin verwendet. Wenn nicht, sollte Ihre Schriftart betriebsbereit sein.

Ich habe die Methode zur Erkennung des Ladens von Schriftarten in ein jQuery-Plugin umgeschrieben, das dem Entwickler die Möglichkeit gibt, Elemente basierend darauf zu formatieren, ob die Schrift geladen wurde oder nicht. Ein ausfallsicherer Timer wurde hinzugefügt, damit der Benutzer nicht ohne Inhalt bleibt, wenn die benutzerdefinierte Schriftart nicht geladen werden kann. Das ist nur schlechte Benutzerfreundlichkeit.

Ich habe auch eine bessere Kontrolle darüber hinzugefügt, was beim Laden von Schriftarten und beim Fehlschlagen passiert, indem Klassen hinzugefügt und entfernt werden. Sie können jetzt mit der Schriftart tun, was Sie möchten. Ich würde nur empfehlen, die Schriftgröße, den Zeilenabstand usw. zu ändern, um Ihre Fallback-Schrift so nah wie möglich an die benutzerdefinierte Schrift zu bringen, damit Ihr Layout intakt bleibt und die Benutzer eine erwartete Erfahrung erhalten.

Hier ist eine Demo: http://patrickmarabeas.github.io/jQuery-FontSpy.js

Wirf das Folgende in eine .js-Datei und verweise darauf.

(function($) {

    $.fontSpy = function( element, conf ) {
        var $element = $(element);
        var defaults = {
            font: $element.css("font-family"),
            onLoad: '',
            onFail: '',
            testFont: 'Comic Sans MS',
            testString: 'QW@HhsXJ',
            delay: 50,
            timeOut: 2500
        };
        var config = $.extend( defaults, conf );
        var tester = document.createElement('span');
            tester.style.position = 'absolute';
            tester.style.top = '-9999px';
            tester.style.left = '-9999px';
            tester.style.visibility = 'hidden';
            tester.style.fontFamily = config.testFont;
            tester.style.fontSize = '250px';
            tester.innerHTML = config.testString;
        document.body.appendChild(tester);
        var fallbackFontWidth = tester.offsetWidth;
        tester.style.fontFamily = config.font + ',' + config.testFont;
        function checkFont() {
            var loadedFontWidth = tester.offsetWidth;
            if (fallbackFontWidth === loadedFontWidth){
                if(config.timeOut < 0) {
                    $element.removeClass(config.onLoad);
                    $element.addClass(config.onFail);
                    console.log('failure');
                }
                else {
                    $element.addClass(config.onLoad);
                    setTimeout(checkFont, config.delay);
                    config.timeOut = config.timeOut - config.delay;
                }
            }
            else {
                $element.removeClass(config.onLoad);
            }
        }
        checkFont();
    };

    $.fn.fontSpy = function(config) {
        return this.each(function() {
            if (undefined == $(this).data('fontSpy')) {
                var plugin = new $.fontSpy(this, config);
                $(this).data('fontSpy', plugin);
            }
        });
    };

})(jQuery);

Wenden Sie es auf Ihr Projekt an

.bannerTextChecked {
        font-family: "Lobster";
        /* don't specify fallback font here, do this in onFail class */
}

$(document).ready(function() {

    $('.bannerTextChecked').fontSpy({
        onLoad: 'hideMe',
        onFail: 'fontFail anotherClass'
    });

});

Entfernen Sie diese FOUC!

.hideMe {
    visibility: hidden !important;
}

.fontFail {
    visibility: visible !important;
    /* fall back font */
    /* necessary styling so fallback font doesn't break your layout */
}

BEARBEITEN: Die FontAwesome-Kompatibilität wurde entfernt, da sie nicht richtig funktionierte und Probleme mit verschiedenen Versionen auftraten. Eine hackige Lösung finden Sie hier: https://github.com/patrickmarabeas/jQuery-FontFaceSpy.js/issues/1

Patrick
quelle
Schriftlängen vergleichen ... Ist dies auch das, was WebFont Loader (siehe die andere Antwort) tut?
Pacerier
1
In jedem Fall funktioniert das Vergleichen der Zeichenlängen bei vielen Schriftarten nicht, da viele "Kopier" -Schriftarten gleich lang sind . Zum Beispiel haben Arial, Helvetica und Liberation Sans alle identische Zeichenbreiten für alle Zeichen. Siehe auch en.wikipedia.org/wiki/Arial . Bisher scheint es, als ob die Pixel-für-Pixel-Überprüfung mit Canvas die einzige
narrensichere
1
Ich musste dies verwenden, um ein Problem zu beheben, das ich mit iScroll hatte, als ich die Größe der Elemente berechnete, die vor dem Laden der Schriftarten falsch waren. Aber ich benutze jQuery nicht, also habe ich eine Vanille-js-Version erstellt: github.com/keithswright/vanilla-fontspy scheint für mich zu funktionieren.
Keith
@Pacerier - Beachten Sie, dass nur Ihr gewählter Test und Ihre gewählte Ladeschrift unterschiedliche Längen haben müssen. Sofern Comic Sans nicht viele Schriftarten hat, mit denen die Zeichenbreite identisch ist, sollte dies in den meisten Fällen dennoch funktionieren.
BryanGrezeszak
20

Probieren Sie den von Google und Typekit entwickelten WebFont Loader ( Github Repo ) aus.

In diesem Beispiel wird zuerst der Text in der Standard-Serifenschrift angezeigt. Nachdem die Schriftarten geladen wurden, wird der Text in der angegebenen Schriftart angezeigt. (Dieser Code gibt das Standardverhalten von Firefox in allen anderen modernen Browsern wieder.)

cassi.lup
quelle
9

Hier ist ein anderer Ansatz für die Lösungen als für andere.

Ich verwende FontAwesome 4.1.0, um WebGL-Texturen zu erstellen. Das brachte mich auf die Idee, eine winzige Leinwand zum Rendern eines Fa-Quadrats zu verwenden und dann ein Pixel in dieser Leinwand zu überprüfen, um zu testen, ob es geladen wurde:

function waitForFontAwesome( callback ) {
   var retries = 5;

   var checkReady = function() {
      var canvas, context;
      retries -= 1;
      canvas = document.createElement('canvas');
      canvas.width = 20;
      canvas.height = 20;
      context = canvas.getContext('2d');
      context.fillStyle = 'rgba(0,0,0,1.0)';
      context.fillRect( 0, 0, 20, 20 );
      context.font = '16pt FontAwesome';
      context.textAlign = 'center';
      context.fillStyle = 'rgba(255,255,255,1.0)';
      context.fillText( '\uf0c8', 10, 18 );
      var data = context.getImageData( 2, 10, 1, 1 ).data;
      if ( data[0] !== 255 && data[1] !== 255 && data[2] !== 255 ) {
         console.log( "FontAwesome is not yet available, retrying ..." );
         if ( retries > 0 ) {
            setTimeout( checkReady, 200 );
         }
      } else {
         console.log( "FontAwesome is loaded" );
         if ( typeof callback === 'function' ) {
            callback();
         }
      }
   }

   checkReady();
};

Da es eine Zeichenfläche verwendet, ist ein ziemlich moderner Browser erforderlich, aber möglicherweise funktioniert es auch mit IE8 mit der Polyfüllung.

Leeft
quelle
Ich habe das gleiche Problem beim Laden von font-awesome in KonvaJS
Mahdi Alkhatib
4

Eigentlich gibt es eine gute Möglichkeit zu verstehen, dass alle Schriftarten anfangen, vollständig heruntergeladen oder geladen zu werden oder nicht und in einige Fehler geraten. Beachten Sie jedoch nicht nur für eine bestimmte Schriftart den folgenden Code:

document.fonts.onloading = () => {
  // do someting when fonts begin to download
};
document.fonts.onloadingdone = () => {
  // do someting when fonts are loaded completely
};
document.fonts.onloading = () => {
  // do someting when fonts fall into some error
};

Und es gibt auch eine Option, die zurückgibt Promiseund mit der .thenFunktion umgehen kann:

document.fonts.ready
 .then(() => console.log('do someting at the final with each status'))
AmerllicA
quelle
Vielen Dank. es funktioniert total! Aber ich muss das Laden der Schrift auslösen, indem ich irgendwo ein <span> -Element platziere, das diese Schrift verwendet.
tyt2y3
wird in IE11 nicht unterstützt, das leider immer noch im Lieferumfang von Windows Server
Guy Passy enthalten ist.
@ GuyPassy, ​​ich weiß nicht, was der IE11 ist !!
AmerllicA
4
@AmerllicA Ich wünschte, ich könnte eines Tages so viel Glück haben
Guy Passy
3

Hier ist eine andere Möglichkeit, um festzustellen, ob ein @ font-face bereits geladen wurde, ohne dass Timer verwendet werden müssen: Verwenden Sie ein "Bildlauf" -Ereignis, um ein sofortiges Ereignis zu erhalten, wenn die Größe eines sorgfältig gestalteten Elements geändert wird.

Ich habe einen Blog-Beitrag darüber geschrieben, wie es gemacht wird, und die Bibliothek auf Github veröffentlicht .

smnh
quelle
0

Versuchen Sie etwas wie

$(window).bind("load", function() {
       $('#text').addClass('shown');
});

und dann tun

#text {visibility: hidden;}
#text.shown {visibility: visible;}

Das Ladeereignis sollte ausgelöst werden, nachdem die Schriftarten geladen wurden.

hayk.mart
quelle
Dies gilt auch für das $(function(){...})Laden der gesamten Seite.
Shankar Cabus
1
Es ist nicht das Gleiche. Das Beispiel von hayk.mart wird ausgelöst, wenn die DOM- (HTML) UND-Assets auf der Seite (CSS, JS, Bilder, Frames) vollständig geladen sind. Ihr Beispiel, wenn nur das DOM vollständig geladen wurde.
Blaise
Neugierig, warum diese Antwort abgelehnt wird, zeigt eine schnelle Suche, dass es der richtige Ansatz ist, z. B. eifrig.io/blog/how-to-decide-when-your-code-should-run
-1

Dies ist ein alternativer Ansatz, der zumindest sicherstellt, dass font-awesome geladen wird, NICHT eine vollständige Lösung für das OP. Originalcode in den WordPress-Foren hier https://wordpress.stackexchange.com/a/165358/40636 .

Es ist agnostisch und funktioniert mit jeder Schriftartressource wie font-awesome, bei der eine Schriftfamilie überprüft werden kann. Mit ein wenig mehr Gedanken wette ich, dass dies auf viel mehr angewendet werden könnte ...

<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<script>
    (function($){
        var faSpan = $('<span class="fa" style="display:none"></span>').appendTo('body');
        if (faSpan .css('fontFamily') !== 'FontAwesome' ) {
            // Fallback Link
            $('head').append('<link href="https://stackoverflow.com/css/font-awesome.min.css" rel="stylesheet">');
        }
        faSpan.remove();
    })(jQuery);
</script>
oucil
quelle
Dies ist ein Fallback für den Fall, dass Font-Awesome nicht geladen wird (oder wenn es zu langsam geladen wird! ), Aber nicht benachrichtigt, wenn die Schrift vollständig geladen wurde.
Dan Dascalescu
@DanDascalescu Ich habe die Antwort aktualisiert, um deutlicher darauf hinzuweisen, dass dies ein alternativer Ansatz ist, der nur sicherstellt, dass die Bibliothek mit den fantastischen Schriftarten geladen wird, und keine vollständige Lösung. Hoffentlich klärt das ein bisschen auf, da ich einige Downvotes aus der vorherigen Iteration verdient habe.
Oucil
-3

Verwenden Sie den folgenden Code:

<!DOCTYPE HTML>
<html>
    <head>
    </head>

<body>
<canvas id="canvasFont" width="40px" height="40px" style="position: absolute; display: none;"></canvas>

<script>
function IsLoadedFonts()
    {
        var Args = arguments;
        var obj = document.getElementById('canvasFont');
        var ctx = obj.getContext("2d");
        var baseFont = (/chrome/i.test(navigator.userAgent))?'tims new roman':'arial';
         //................
          function getImg(fon)
          { 
            ctx.clearRect(0, 0, (obj).width, (obj).height);
            ctx.fillStyle = 'rgba(0,0,0,1.0)';
            ctx.fillRect( 0, 0, 40, 40 );
            ctx.font = '20px '+ fon;
            ctx.textBaseline = "top";
            ctx.fillStyle = 'rgba(255,255,255,1.0)';
            ctx.fillText( '\u0630', 18, 5 );
            return ctx.getImageData( 0, 0, 40, 40 );
          };
        //..............
          for(var i1=0; i1<Args.length; i1++)
          {
            data1 = getImg(Args[i1]);
            data2 = getImg(baseFont);
            var isLoaded = false;
            //...........
            for (var i=0; i<data1.data.length; i++)
            {
                if(data1.data[i] != data2.data[i])
                    {isLoaded = true; break;}
            }
            //..........
            if(!isLoaded)
                    return false;
         }
         return true;
    };

     setTimeout(function(){alert(IsLoadedFonts('myfont'));},100);
   </script>
   </body>

Kann viele Schriftarten überprüfen:

setTimeout(function(){alert(IsLoadedFonts('font1','font2','font3'));},100);

Der folgende Code funktioniert nur in der Oper, ist aber einfach:

if(!document.defaultView.getComputedStyle(document.getElementById('mydiv'))['fontFamily'].match(/myfont/i))
          alert("font do not loaded ");
Ali Bagheri
quelle