Как узнать, загружен ли шрифт (@font-face)?

Я использую Font-Awesome, но в то время как файлы шрифтов не загружаются, значки появляются с помощью .

Итак, я хочу, чтобы эти значки имели display:none, а файлы не загружались.

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

Как узнать, что эти файлы были загружены, и я наконец смог показать значки?

Edit: Я не говорю, когда страница загружается (загружается), потому что шрифт может быть загружен до всей страницы.

Ответ 1

Теперь на GitHub: https://github.com/patrickmarabeas/jQuery-FontSpy.js

По существу метод работает, сравнивая ширину строки в двух разных шрифтах. Мы используем Comic Sans в качестве шрифта для тестирования, потому что это самые разные веб-безопасные шрифты и, надеюсь, достаточно разные для любого пользовательского шрифта, который вы будете использовать. Кроме того, мы используем очень большой размер шрифта, поэтому заметны даже небольшие различия. Когда была рассчитана ширина строки Comic Sans, семейство шрифтов будет изменено на ваш пользовательский шрифт с отступлением от Comic Sans. Когда отмечено, если ширина строкового элемента одинакова, резервный шрифт Comic Sans все еще используется. Если нет, ваш шрифт должен работать.

Я переписал метод обнаружения загрузки шрифтов в плагин jQuery, предназначенный для того, чтобы дать разработчику возможность стилизовать элементы на основе того, загружен ли шрифт или нет. Добавлен таймер с безопасностью, поэтому пользователь не остается без содержимого, если пользовательский шрифт не загружается. Это просто плохое использование.

Я также добавил больше контроля над тем, что происходит во время загрузки шрифта и при неудаче с включением добавления и удаления классов. Теперь вы можете делать все, что захотите. Я бы рекомендовал только изменить размер шрифта, межстрочный интервал и т.д., Чтобы вернуть шрифт отскока как можно ближе к таможне, чтобы ваш макет оставался неповрежденным, и пользователи получают ожидаемый опыт.

Вот демо: http://patrickmarabeas.github.io/jQuery-FontSpy.js

Добавьте в файл .js следующее:

(function($) {

    $.fontSpy = function( element, conf ) {
        var $element = $(element);
        var defaults = {
            font: $element.css("font-family"),
            onLoad: '',
            onFail: '',
            testFont: 'Comic Sans MS',
            testString: '[email protected]',
            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);

Примените его к вашему проекту

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

});

Удалите эту FOUC!

.hideMe {
    visibility: hidden !important;
}

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

EDIT: совместимость с FontAwesome удалена, так как она не работает должным образом и сталкивается с проблемами с разными версиями. Хакерное исправление можно найти здесь: https://github.com/patrickmarabeas/jQuery-FontFaceSpy.js/issues/1

Ответ 2

Попробуйте WebFont Loader (github repo), разработанный Google и Typekit.

Этот пример сначала отображает текст в шрифте по умолчанию serif; затем после загрузки шрифтов отображается текст в указанном шрифте. (Этот код воспроизводит поведение по умолчанию Firefox во всех других современных браузерах.)

Ответ 3

Вот другой подход к решениям от других.

Я использую FontAwesome 4.1.0 для создания текстур WebGL. Это дало мне идею использовать крошечный холст для рендеринга fa-квадрата, а затем проверить пиксель в этом холсте, чтобы проверить, загрузился ли он:

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

Поскольку он использует холст, для него требуется довольно современный браузер, но он может работать и с IE8 с помощью polyfill.

Ответ 4

Здесь еще один способ узнать, была ли уже загружена @font-face без использования таймеров вообще: используйте событие "прокрутки", чтобы получить мгновенное событие, когда изменяется размер тщательно обработанного элемента.

Я написал сообщение о том, как он это сделал, и опубликовал библиотеки на Github.

Ответ 5

Это альтернативный подход, который по крайней мере обеспечит загрузку шрифта, НЕ полное решение для OP. Исходный код найден на форумах Wordpress здесь https://wordpress.stackexchange.com/a/165358/40636.

Он агностик и будет работать с любым ресурсом стиля шрифта, например, шрифтом, где можно проверить семейство шрифтов. С небольшим количеством мысли я уверен, что это может быть применено к гораздо более...

<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="/css/font-awesome.min.css" rel="stylesheet">');
        }
        faSpan.remove();
    })(jQuery);
</script>

Ответ 6

Используйте приведенный ниже код:

<!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>

Можно проверить многие шрифты:

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

Нижеприведенный код работает только в опера, но легко:

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

Ответ 7

Попробуйте что-нибудь вроде

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

а затем do

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

Событие загрузки должно запускаться после загрузки шрифтов.