Как узнать, загружен ли шрифт (@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;
}
Как я узнаю, что эти файлы были загружены, и я наконец-то смог показать значки?
Редактировать: я не говорю, когда страница загружена (onload), потому что шрифт может быть загружен до всей страницы.
10 ответов
Теперь на 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: '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);
Примените это к своему проекту
.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 */
}
РЕДАКТИРОВАТЬ: FontAwesome совместимость удалена, поскольку она не работает должным образом и столкнулся с проблемами с различными версиями. Хакерское исправление можно найти здесь: https://github.com/patrickmarabeas/jQuery-FontFaceSpy.js/issues/1
Попробуйте WebFont Loader ( github repo), разработанный Google и Typekit.
В этом примере сначала отображается текст шрифтом с засечками по умолчанию; затем после загрузки шрифтов отображается текст указанным шрифтом. (Этот код воспроизводит поведение Firefox по умолчанию во всех других современных браузерах.)
На самом деле, есть хороший способ понять, что все шрифты начинают загружаться или загружаются полностью или нет и выдают некоторые ошибки, но это не только для конкретного шрифта, обратите внимание на следующий код:
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
};
А также есть вариант, который возвращает Promise
и он мог справиться с .then
функция:
document.fonts.ready
.then(() => console.log('do someting at the final with each status'))
Здесь другой подход к решениям от других.
Я использую FontAwesome 4.1.0 для создания текстур WebGL. Это дало мне идею использовать крошечный холст для рендеринга фа-квадрата, а затем проверить пиксель на этом холсте, чтобы проверить, загрузился ли он:
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 с полифилом.
Вот еще один способ узнать, был ли @font-face уже загружен без использования таймеров вообще: использовать событие "прокрутка", чтобы получить мгновенное событие, когда размер тщательно созданного элемента изменяется.
Я написал сообщение в блоге о том, как это делается, и опубликовал библиотеку на Github.
Попробуйте что-то вроде
$(window).bind("load", function() {
$('#text').addClass('shown');
});
а затем сделать
#text {visibility: hidden;}
#text.shown {visibility: visible;}
Событие load должно сработать после загрузки шрифтов.
в качестве альтернативы вы можете добавить
font-display: block
к вашему объявлению @font-face.
это указывает браузерам отображать резервный шрифт как невидимый до тех пор, пока ваш шрифт не будет загружен, нет необходимости
display: none
или любое обнаружение шрифта загрузки javascript
Решение для Typescript, Angular.
Если вы работаете с Angular, вы можете использовать этот модуль для проверки шрифтов.
// document.fonts.check extension
import type {} from 'css-font-loading-module';
ngOnInit() {
this.onFontLoad();
}
public onFontLoad() {
let myTimer = setInterval(() => {
if (document.fonts.check('14px MyFont')) {
console.log('Font is loaded!');
clearInterval(myTimer);
} else {
console.log('Font is loading');
}
}, 1);
}
Кроме того, некоторые шрифты очень тяжелые. Таким образом, вы можете добавить экран загрузки во время загрузки шрифта и удалить экран загрузки при загрузке шрифта. Я считаю, что это лучший подход, чем изменение вашего класса CSS на
display: none
, просто потому, что загрузка некоторых шрифтов может занять 3-4+ секунды, если у пользователя медленный интернет.
Это альтернативный подход, который, по крайней мере, гарантирует загрузку font-awesome, а не полное решение OP. Оригинальный код найден на форумах WordPress здесь https://wordpress.stackexchange.com/a/165358/40636.
Он независим и будет работать с любым ресурсом стиля шрифта, например font-awesome, где можно проверить семейство шрифтов. Если немного подумать, держу пари, это может быть применено к гораздо большему...
<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>
Используйте код ниже:
<!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 ");