¿Cómo saber si ya se ha cargado una fuente (@font-face)?

Resuelto Shankar Cabus asked hace 12 años • 10 respuestas

Estoy usando Font-Awesome, pero mientras los archivos de fuentes no están cargados, los íconos aparecen con .

Entonces, quiero que estos íconos tengan display:nonemientras los archivos no estén cargados.

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

¿Cómo sé que estos archivos se han cargado y finalmente puedo mostrar los íconos?

Editar: no estoy hablando cuando la página está cargada (onload), porque la fuente podría cargarse antes que toda la página.

Shankar Cabus avatar Sep 07 '12 12:09 Shankar Cabus
Aceptado

Ahora en GitHub: https://github.com/patrickmarabeas/jQuery-FontSpy.js

Básicamente, el método funciona comparando el ancho de una cadena en dos fuentes diferentes. Estamos utilizando Comic Sans como fuente para realizar pruebas, porque es la más diferente de las fuentes seguras para la web y, con suerte, lo suficientemente diferente a cualquier fuente personalizada que vaya a utilizar. Además, utilizamos un tamaño de fuente muy grande, por lo que incluso las pequeñas diferencias serán evidentes. Cuando se ha calculado el ancho de la cadena Comic Sans, la familia de fuentes se cambia a su fuente personalizada, con un respaldo a Comic Sans. Cuando está marcada, si el ancho del elemento de cadena es el mismo, la fuente alternativa de Comic Sans todavía está en uso. De lo contrario, su fuente debería estar operativa.

Reescribí el método de detección de carga de fuentes en un complemento jQuery diseñado para brindarle al desarrollador la capacidad de diseñar elementos según si la fuente se ha cargado o no. Se agregó un temporizador a prueba de fallas para que el usuario no se quede sin contenido si la fuente personalizada no se carga. Eso es simplemente mala usabilidad.

También agregué un mayor control sobre lo que sucede durante la carga de fuentes y en caso de falla con la inclusión de la adición y eliminación de clases. Ahora puedes hacer lo que quieras con la fuente. Solo recomendaría modificar el tamaño de las fuentes, el interlineado, etc. para que la fuente alternativa sea lo más cercana posible a la personalizada, de modo que el diseño permanezca intacto y los usuarios obtengan la experiencia esperada.

Aquí hay una demostración: http://patrickmarabeas.github.io/jQuery-FontSpy.js

Coloque lo siguiente en un archivo .js y haga referencia a él.

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

Aplícalo a tu proyecto

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

});

¡Quita ese FOUC!

.hideMe {
    visibility: hidden !important;
}

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

EDITAR: Se eliminó la compatibilidad con FontAwesome porque no funcionó correctamente y tuvo problemas con diferentes versiones. Puede encontrar una solución hacky aquí: https://github.com/patrickmarabeas/jQuery-FontFaceSpy.js/issues/1

Patrick avatar Sep 07 '2012 10:09 Patrick

Pruebe WebFont Loader ( repositorio de github ), desarrollado por Google y Typekit.

Este ejemplo primero muestra el texto en la fuente serif predeterminada; luego, una vez cargadas las fuentes, muestra el texto en la fuente especificada. (Este código reproduce el comportamiento predeterminado de Firefox en todos los demás navegadores modernos).

cassi.lup avatar Sep 07 '2012 05:09 cassi.lup

En realidad, hay una buena manera de entender que todas las fuentes comienzan a descargarse o cargarse por completo o no y caen en algunos errores, pero no es solo para una fuente específica , preste atención al siguiente código:

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

Y también hay una opción que regresa Promisey podría manejarse con .thenla función:

document.fonts.ready
 .then(() => console.log('do someting at the final with each status'))
AmerllicA avatar Mar 03 '2020 21:03 AmerllicA

Aquí hay un enfoque diferente a las soluciones que los demás.

Estoy usando FontAwesome 4.1.0 para crear texturas WebGL. Eso me dio la idea de usar un lienzo pequeño para representar un cuadrado fa y luego verificar un píxel en ese lienzo para comprobar si se ha cargado:

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

Como utiliza un lienzo, requiere un navegador bastante moderno, pero podría funcionar también en IE8 con polyfill.

Leeft avatar Jul 07 '2014 19:07 Leeft