The Problem of Detecting Webfont Application

2015-11-23 | #javascript, #solution, #webdev

Detecting if a webfont is loaded is one thing ... a very stupid thing ... because it doesn't help one bit. What we'll always want to know is, when the font is really applied to the page, therefore actually visible and thereby as well altering the page's layout.

And that's a little bit tricky.

In general there are two viable solutions:

Either you go oldschool and poll the state of a text block determining its dimensions in comparison to a system font:

function waitForWebfonts(fonts, callback, fallbackFontName) {

fonts = $.isArray(fonts) ? fonts : [''+fonts];

fallbackFontName = fallbackFontName || 'sans-serif';

var loadedFonts = 0;

$.each(fonts, function(index, font){

var $node = $('<span></span>')

.html('giItT1WQy@!-/#')

.css({

'position' : 'absolute',

'visibility' : 'hidden',

'left' : '-10000px',

'top' : '-10000px',

'font-size' : '300px',

'font-family' : fallbackFontName,

'font-variant' : 'normal',

'font-style' : 'normal',

'font-weight' : 'normal',

'letter-spacing' : '0',

'white-space' : 'pre'

})

;

$('body').append($node);

var systemFontWidth = $node.width();

$node.css('font-family', font+', '+fallbackFontName);

var tCheckFontLoaded = null;

var fCheckFont = function(){

if( $node && ($node.width() != systemFontWidth) ){

loadedFonts++;

$node.remove();

$node = null;

}

if( loadedFonts >= fonts.length ){

if( tCheckFontLoaded !== null ){

window.clearInterval(tCheckFontLoaded);

}

if(

(loadedFonts == fonts.length)

&& (deferred.state() != 'resolved')

){

if( $.isFunction(callback) ){

callback();

}

return true;

}

}

return false;

};

if( !fCheckFont() ){

tCheckFontLoaded = window.setInterval(fCheckFont, 50);

}

});

};

Or you go all web 2.0 and dynamically render a canvas-based image, containing a rendered text of the expected font and compare the canvas contents.

function IsLoadedFonts(){

var Args = arguments;

var obj = document.getElementById('canvasFont');

var ctx = obj.getContext("2d");

var baseFont = (/chrome/i.test(navigator.userAgent)) ? 'times 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 );

};

var data2 = getImg(baseFont);

for( var i1=0; i1<Args.length; i1++ ){

var data1 = getImg(Args[i1]);

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