Làm thế nào để biết liệu một phông chữ (@ font-face) đã được tải chưa?


81

Tôi đang sử dụng Font-Awesome, nhưng trong khi các tệp phông chữ không được tải, các biểu tượng sẽ xuất hiện với .

Vì vậy, tôi muốn các biểu tượng này có display:nonetrong khi các tệp không được tải.

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

Làm cách nào để biết rằng các tệp này đã được tải và cuối cùng tôi có thể hiển thị các biểu tượng?

Chỉnh sửa: Tôi không nói khi trang được tải (onload), vì phông chữ có thể được tải trước toàn bộ trang.


Hy vọng rằng chúng ta có thể có các sự kiện phông chữ mẹ đẻ sớm blog.typekit.com/2013/02/05/more-reliable-font-events
Pacerier


2
Câu hỏi này trùng lặp và tôi đã đăng câu trả lời cập nhật năm 2015 cho câu hỏi ban đầu.
Dan Dascalescu,

Có một giải pháp sử dụng tính năng phát hiện cuộn tại smnh.me/web-font-loading-detection-without-timers
Pacerier

Câu trả lời:


44

Hiện có trên GitHub: https://github.com/patrickmarabeas/jQuery-FontSpy.js

Về cơ bản, phương pháp hoạt động bằng cách so sánh độ rộng của một chuỗi trong hai phông chữ khác nhau. Chúng tôi đang sử dụng Comic Sans làm phông chữ để thử nghiệm, bởi vì nó là phông chữ khác biệt nhất trong số các phông chữ an toàn trên web và hy vọng đủ khác với bất kỳ phông chữ tùy chỉnh nào bạn sẽ sử dụng. Ngoài ra, chúng tôi đang sử dụng kích thước phông chữ rất lớn vì vậy những khác biệt dù là nhỏ cũng sẽ rõ ràng. Khi chiều rộng của chuỗi Comic Sans đã được tính toán, họ phông chữ được thay đổi thành phông chữ tùy chỉnh của bạn, với dự phòng là Comic Sans. Khi được kiểm tra, nếu chiều rộng phần tử chuỗi giống nhau, thì phông chữ dự phòng của Comic Sans vẫn đang được sử dụng. Nếu không, phông chữ của bạn sẽ hoạt động.

Tôi đã viết lại phương pháp phát hiện tải phông chữ thành một plugin jQuery được thiết kế để cung cấp cho nhà phát triển khả năng định kiểu các phần tử dựa trên việc phông chữ đã được tải hay chưa. Một bộ hẹn giờ an toàn không thành công đã được thêm vào để người dùng không bị bỏ mặc nếu không tải được phông chữ tùy chỉnh. Đó chỉ là khả năng sử dụng kém.

Tôi cũng đã thêm quyền kiểm soát tốt hơn những gì xảy ra trong quá trình tải phông chữ và không thành công với việc bao gồm thêm và xóa các lớp. Bây giờ bạn có thể làm bất cứ điều gì bạn thích với phông chữ. Tôi chỉ khuyên bạn nên sửa đổi kích thước phông chữ, khoảng cách dòng, v.v. để phông chữ thu lại của bạn gần với tùy chỉnh nhất có thể để bố cục của bạn vẫn nguyên vẹn và người dùng có được trải nghiệm như mong đợi.

Đây là bản demo: http://patrickmarabeas.github.io/jQuery-FontSpy.js

Ném phần sau vào tệp .js và tham chiếu nó.

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

Áp dụng nó vào dự án của bạn

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

});

Loại bỏ FOUC đó!

.hideMe {
    visibility: hidden !important;
}

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

CHỈNH SỬA: Đã xóa khả năng tương thích của FontAwesome vì nó không hoạt động bình thường và gặp sự cố với các phiên bản khác nhau. Có thể tìm thấy bản sửa lỗi hack tại đây: https://github.com/patrickmarabeas/jQuery-FontFaceSpy.js/issues/1


So sánh độ dài phông chữ ... Đây có phải là những gì WebFont Loader (xem câu trả lời khác) đang làm không?
Pacerier

1
Và trong mọi trường hợp, việc so sánh độ dài ký tự sẽ không hoạt động đối với nhiều phông chữ vì nhiều phông chữ "sao chép" được thiết kế để có độ dài bằng nhau . Ví dụ: Arial, Helvetica và Liberation Sans đều có độ rộng ký tự giống nhau cho tất cả các ký tự. Cũng xem en.wikipedia.org/wiki/Arial . Cho đến nay, có vẻ như kiểm tra pixel cho từng pixel bằng canvas có thể là lựa chọn chống đánh lừa duy nhất .....
Pacerier

1
Tôi cần sử dụng điều này để khắc phục sự cố mà tôi gặp phải với iScroll khi tính toán sai kích thước của các phần tử trước khi tải phông chữ. Nhưng tôi không sử dụng jQuery, vì vậy tôi đã tạo phiên bản js vani: github.com/keithswright/vanilla-fontspy dường như phù hợp với tôi.
Keith

@Pacerier - lưu ý rằng chỉ thử nghiệm bạn đã chọn và phông chữ tải đã chọn của bạn cần có độ dài khác nhau. Vì vậy, trừ khi Comic Sans có rất nhiều phông chữ có độ rộng ký tự giống hệt nhau, điều này vẫn sẽ hoạt động trong hầu hết các trường hợp.
BryanGrezeszak 19/12/16

20

Hãy thử WebFont Loader ( github repo ), được phát triển bởi Google và Typekit.

Ví dụ này đầu tiên hiển thị văn bản trong phông chữ serif mặc định; thì sau khi các phông chữ đã được tải, nó sẽ hiển thị văn bản trong phông chữ được chỉ định. (Mã này tái tạo hành vi mặc định của Firefox trong tất cả các trình duyệt hiện đại khác.)


9

Đây là một cách tiếp cận khác với các giải pháp từ những người khác.

Tôi đang sử dụng FontAwesome 4.1.0 để tạo kết cấu WebGL. Điều đó đã cho tôi ý tưởng sử dụng một canvas nhỏ để hiển thị hình vuông fa, sau đó kiểm tra một pixel trong canvas đó để kiểm tra xem nó đã được tải chưa:

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

Vì nó sử dụng canvas nên nó yêu cầu một trình duyệt khá hiện đại, nhưng nó có thể hoạt động trên IE8 cũng như với polyfill.


Tôi đang phải đối mặt với cùng một vấn đề khi tải font-tuyệt vời trong KonvaJS
Mahdi Alkhatib

4

Trên thực tế, có một cách tốt để hiểu tất cả các phông chữ bắt đầu tải xuống hoặc tải hoàn toàn hay không và rơi vào một số lỗi, nhưng nó không chỉ dành cho một phông chữ cụ thể , hãy chú ý đến đoạn mã sau:

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

Và cũng có một tùy chọn trả về Promisevà nó có thể xử lý với .thenchức năng:

document.fonts.ready
 .then(() => console.log('do someting at the final with each status'))

cảm ơn bạn. nó hoàn toàn hoạt động! Nhưng tôi cần kích hoạt tải phông chữ bằng cách đặt một phần tử <span> sử dụng phông chữ đó ở đâu đó.
tyt2y3

không được hỗ trợ trong IE11, tiếc là vẫn đi kèm với Windows Server
Guy Passy

@GuyPassy, ​​tôi không biết IE11 là gì !!
AmerllicA

4
@AmerllicA Tôi ước một ngày nào đó mình có thể may mắn như vậy
Guy Passy

3

Đây là một cách khác để biết liệu @ font-face đã được tải hay chưa mà không cần phải sử dụng bộ hẹn giờ: sử dụng sự kiện "cuộn" để nhận sự kiện tức thì khi kích thước của phần tử được chế tạo cẩn thận được thay đổi.

Tôi đã viết một bài đăng trên blog về cách nó được thực hiện và đã xuất bản thư viện trên Github .


0

Hãy thử một cái gì đó như

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

và sau đó làm

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

Sự kiện tải sẽ kích hoạt sau khi các phông chữ được tải.


Điều này giống như $(function(){...})chạy khi toàn bộ trang được tải.
Shankar Cabus

1
nó không giống nhau. Ví dụ của hayk.mart sẽ kích hoạt khi nội dung DOM (HTML) VÀ bên trong trang (CSS, JS, hình ảnh, khung) được tải xong. Ví dụ của bạn khi chỉ DOM tải xong.
Blaise

Tò mò tại sao câu trả lời này là downvoted, một cách nhanh chóng các chương trình tìm kiếm đó là cách tiếp cận đúng, ví dụ như eager.io/blog/how-to-decide-when-your-code-should-run

-1

Đây là một cách tiếp cận thay thế ít nhất sẽ đảm bảo rằng font-awesome được tải, KHÔNG PHẢI là một giải pháp hoàn chỉnh cho OP. Mã gốc được tìm thấy trong các diễn đàn wordpress tại đây https://wordpress.stackexchange.com/a/165358/40636 .

Nó bất khả tri và sẽ hoạt động với bất kỳ tài nguyên kiểu phông chữ nào như phông chữ-awesome, nơi có thể kiểm tra họ phông chữ. Với một chút suy nghĩ, tôi cá rằng điều này có thể được áp dụng cho nhiều hơn nữa ...

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

Đây là dự phòng trong trường hợp Font-Awesome không tải (hoặc nếu tải quá chậm! ), Nhưng không thông báo khi phông chữ tải xong.
Dan Dascalescu

@DanDascalescu Tôi đã cập nhật câu trả lời để chỉ rõ hơn rằng đây là một cách tiếp cận thay thế chỉ đảm bảo rằng thư viện phông chữ tuyệt vời được tải chứ không phải là một giải pháp hoàn chỉnh. Hy vọng rằng điều đó sẽ rõ ràng hơn một chút, vì tôi đã kiếm được một số phiếu phản đối từ lần lặp trước.
oucil

-3

Sử dụng mã dưới đây:

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

Có thể kiểm tra nhiều phông chữ:

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

Đoạn mã dưới đây chỉ hoạt động trong opera nhưng rất dễ dàng:

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

Cùng một ý tưởng "render to canvas" mà Leeft đã đăng một năm trước đó .
Dan Dascalescu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.