web-dev-qa-db-fra.com

Comment savoir si une police (@ font-face) a déjà été chargée?

J'utilise Font-Awesome, mais tant que les fichiers de police ne sont pas chargés, les icônes apparaissent avec.

Donc, je veux que ces icônes aient display:none tant que les fichiers ne sont pas chargés.

@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;
}

Comment savoir si ces fichiers ont été chargés et que je peux enfin afficher les icônes?

Edit: Je ne parle pas lorsque la page est chargée (onload), car la police peut être chargée avant toute la page.

75
Shankar Cabus

Maintenant sur GitHub: https://github.com/patrickmarabeas/jQuery-FontSpy.js

La méthode fonctionne essentiellement en comparant la largeur d'une chaîne dans deux polices différentes. Nous utilisons Comic Sans comme police à utiliser, car il s’agit de la police Web la plus différente et, espérons-le, suffisamment différente de la police que vous utiliserez. De plus, nous utilisons une très grande taille de police, de sorte que même de petites différences apparaîtront. Lorsque la largeur de la chaîne Comic Sans a été calculée, la famille de polices est remplacée par votre police personnalisée, avec un repli sur Comic Sans. Lorsque cette case est cochée, si la largeur de l'élément string est identique, la police de secours de Comic Sans est toujours utilisée. Sinon, votre police devrait être opérationnelle.

J'ai réécrit la méthode de détection du chargement de polices dans un plug-in jQuery conçu pour donner au développeur la possibilité de styliser des éléments en fonction du fait que la police ait été chargée ou non. Un temporisateur de sécurité intégrée a été ajouté pour que l’utilisateur ne reste pas sans contenu si le chargement de la police personnalisée échoue. C’est tout simplement une mauvaise utilisation.

J'ai également ajouté un meilleur contrôle sur ce qui se passe pendant le chargement de la police et sur l'échec avec l'inclusion de l'ajout et de la suppression de classes. Vous pouvez maintenant faire ce que vous voulez à la police. Je ne recommanderais que de modifier la taille des polices, l'interligne, etc. pour que votre police de remplacement soit aussi proche que possible de la coutume afin que votre mise en page reste intacte et que les utilisateurs obtiennent l'expérience attendue.

Voici une démo: http://patrickmarabeas.github.io/jQuery-FontSpy.js

Jetez ce qui suit dans un fichier .js et faites-le référence.

(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);

Appliquez-le à votre projet

.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'
    });

});

Enlevez ce FOUC!

.hideMe {
    visibility: hidden !important;
}

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

EDIT: La compatibilité de FontAwesome a été supprimée car elle ne fonctionnait pas correctement et rencontrait des problèmes avec différentes versions. Un correctif hacky peut être trouvé ici: https://github.com/patrickmarabeas/jQuery-FontFaceSpy.js/issues/1

42
Patrick

Essayez WebFont Loader ( github repo ), développé par Google et Typekit.

Cet exemple affiche d'abord le texte dans la police par défaut du serif; puis, une fois les polices chargées, affiche le texte dans la police spécifiée. (Ce code reproduit le comportement par défaut de Firefox dans tous les autres navigateurs modernes.)

17
cassi.lup

Voici une approche différente des solutions proposées.

J'utilise FontAwesome 4.1.0 pour créer des textures WebGL. Cela m’a donné l’idée d’utiliser un petit canevas pour rendre un carré fa, puis de vérifier un pixel de ce canevas pour vérifier s’il a été chargé:

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();
};

Comme il utilise un canevas, il nécessite un navigateur assez moderne, mais il pourrait également fonctionner sur IE8 avec polyfill.

9
Leeft

Voici un autre moyen de savoir si un @ font-face a déjà été chargé sans avoir à utiliser de minuteur: utilisez un événement "scroll" pour recevoir un événement instantané lorsque la taille d'un élément soigneusement conçu est modifiée.

J'ai écrit un article de blog sur la façon dont c'est fait et j'ai publié le bibliothèque sur Github .

3
smnh