I built a small styling simulator for an app of our company so that designers can quickly check color options/border styles etc for our app.
I used mainly CSSvariables that change when adapting colors via a color picker / adapt values in a config JSON.
The designers should be able to also test different font styles in the JSON but I can't get it to work with local font files.
How can I achieve to load local fonts from a local folder too? I want to achieve this live so that the difference can be seen when entering a different font.
Just loading in example "Courier" works as its a system font but when I want to load it from a folder it doesn't work.
This is how I am loading the fonts into a CSS variable (the get value is just providing a safe method to access the JSON)
JS
$(":root")[0].style.setProperty("--regularFont", "/fonts/" + getValue(parsedConfig,['configs', 0, 'styleSheet', 'fonts', 'regularFont'],"") + ".tff");
$(":root")[0].style.setProperty("--boldFont", "/fonts/" + getValue(parsedConfig,['configs', 0, 'styleSheet', 'fonts', 'boldFont'],"") + ".tff");
JSON:
"fonts": {
"regularFont": "Arial",
"boldFont": "AvenirNext-Bold"
CSS
#font-face {
font-family: sans-serif;
font-family: regularFont;
src: local(var(--regularFont)),
url(var(--regularFont));
}
#font-face {
font-family: sans-serif;
font-family: boldFont;
src: local(var(--boldFont)),
url(var(--boldFont));
font-weight: bold;
}
/* example Styling */
.card {
font-family: regularFont;
}
You can create a FontFace object with the data from the File object and the add it to the document's FontFaceSet:
const fontInput = document.getElementById("font-input"),
test = document.getElementById("test");
let font;
fontInput.addEventListener("input", async () => {
if (font)
document.fonts.remove(font);
const data = await fontInput.files[0].arrayBuffer();
font = new FontFace('test-font', data);
await font.load();
document.fonts.add(font);
test.style.fontFamily = `test-font`;
});
<input type="file" id="font-input">
<p id="test">Upload a font to change me!</p>
Canvas.filltext won't render custom font (though body text will, and canvas.filltext will render local fonts)
I want to paint some text on a canvas, using a custom font called jelleebold. Here's an abbreviated version of the function that I hoped would do that:
function paintLinkNameOnCanvas(linkName, canvas){
let context = canvas.getContext('2d');
context.font = "25px jelleebold";
context.fillText(linkName, 50, 50);
return canvas;
}
However, the font that gets used is whatever the browser (Chrome) uses as its fallback (Times New Roman, I think). Here's the html link
<link href="./CSS/stylesheet.css" rel="stylesheet" type="text/css">
and the css, downloaded from fontsquirrel, and modified to suit my local directory structure:
#font-face {
font-family: jelleebold;
src: url('/fonts/jellee-roman-webfont.woff2') format('woff2'),
url('/fonts/jellee-roman-webfont.woff') format('woff');
font-weight: normal;
font-style: normal;
}
I believe that this has worked, and Jelleebold has loaded successfully, because index.php contains:
<body style ="font-size: 50px; font-family: 'jelleebold'">
<div id= "output" >
test
</div>
etc.
and the word 'test' gets printed in jelleebold.
In contrast, if the paintLinkNameOnCanvas function specifies a font that is installed on the local machine (such as context.font = "25px 'Balford Base'"), the linkname does get painted in that font.
So why isn't the custom font being used to paint the linkname on the canvas?
And after a very helpful suggestion from Renato Bibiano, I've now produced an updated version of the function (shown below). The commented lines are a hint about the next problem; how do I get it to work with both woff- and woff2-formatted fonts? It works with either one, but not the other.
function paintLinkNameOnCanvas(linkName, canvas){
let earl = "";
// earl += "url('/fonts/jellee-roman-webfont.woff' ) format('woff' ";
// earl += ", ";
earl += "url('/fonts/jellee-roman-webfont.woff2')format('woff2')";
let f = new FontFace("jelleebold", earl);
f.load().then(function() {
let context = canvas.getContext('2d');
context.font = '23px jelleebold';
context.fillText('Hey, world', 0, 100);
});
return canvas;
}
I feel that taking the comment slashes out should produce something sensible, but if both specifications (woff and woff2) are included, the ouput reverts to the default font, TNR.
I have a problem with displaying custom icons in IE11 (didn't check for older ones, neither Edge). Chrome and Firefox work properly. Pretty often custom icons that are added to the IconPool are not displayed in IE. After hitting refresh in the browser, they appear normally. Is this a known issue and is there a way to fix this?
The way we do this, is:
Fonts details are stored in a json that is hardcoded in the page source under a specific variable (I've shortened the output and simplified the names):
var myFonts = {
"iconfonts": [{
"content": "ea0f",
"key": "iconFont-icon_search"
}, {
"content": "e635",
"key": "iconFont-burger_close"
}]
}
Then the fonts are loaded by a small utility component (single .js file) method:
addMyFontsToSAPUI5(myFonts);
Code for the utility component:
addMyFontsToSAPUI5 = function(data) {
sap.ui.getCore().attachInit(function() {
setTimeout(function() {
console.log("Loading Icon Fonts");
jQuery.sap.require("sap.ui.core.IconPool");
if (data && data.iconfonts) {
var iconfonts = data.iconfonts;
for (var i = 0; i < iconfonts.length; i++) {
var iconfont = iconfonts[i];
sap.ui.core.IconPool.addIcon(iconfont.key, "myfonts", "iconfont", iconfont.content);
}
console.log("Loading Icons Finished");
var eventBus = sap.ui.getCore().getEventBus();
eventBus.publish("Icons", "IconFontsLoaded");
}
}, 0);
});
};
After the event is raised, components that use these fonts launch the rerender method. Example controller code:
sap.ui.define(
["sap/ui/core/mvc/Controller"],
function(Controller) {
"use strict";
return Controller.extend("mynamespace.controller.Main", {
onInit: function() {
var eventBus = sap.ui.getCore().getEventBus();
eventBus.subscribe("Icons", "IconFontsLoaded", this.onRerender, this);
},
onRerender: function() {
console.log("Rerender after icons are loaded");
this.getView().rerender();
}
});
});
Finally, the CSS structure:
/* My ICONFONT */
#font-face {
font-family: 'iconfont';
src:url('/Fonts/iconfont.eot?-d4jyxw&version=2.1.6');
src:url('/Fonts/iconfont.eot?#iefix-d4jyxw&version=2.1.6') format('embedded-opentype'),
url('/Fonts/iconfont.woff?-d4jyxw&version=2.1.6') format('woff'),
url('/Fonts/iconfont.ttf?-d4jyxw&version=2.1.6') format('truetype'),
url('/Fonts/iconfont.svg?-d4jyxw#iconfont&version=2.1.6') format('svg');
font-weight: normal;
font-style: normal;
}
/* My ICONFONT */
.iconFont {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: 'iconfont' !important;
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.iconFont-icon_search:before {
content: "\ea0f";
}
.iconFont-burger_close:before {
content: "\e635";
}
Every single console.log is launching properly. Somehow firing the rerender method doesn't make the icons reappear. The CSS output is not a regular .css file - it's an output resource generated by a Java component (tho you can display this in the browser under a certain url, but it's not a file physically present on the server).
The components which launch the rerender metod are using the AppCacheBuster.
The application/portal as a whole is working on the SAP Enterprise Portal.
I simply can't determine when exactly this issue occurs, because it seems to happen in some pretty random (seemingly) circumstances. The built-in IconPool icons are always displaying properly.
I'm using Font-Awesome, but while the font files are not loaded, the icons appear with .
So, I want these icons to have display:none while files are not loaded.
#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;
}
How do I know that these files have been loaded and I'm finally able to show the icons?
Edit:
I'm not talking when the page is loaded (onload), because the font could be loaded before the whole page.
Now on GitHub: https://github.com/patrickmarabeas/jQuery-FontSpy.js
Essentially the method works by comparing the width of a string in two different fonts. We are using Comic Sans as the font to test against, because it is the most different of the web safe fonts and hopefully different enough to any custom font you will be using. Additionally we are using a very large font-size so even small differences will be apparent. When the width of the Comic Sans string has been calculated, the font-family is changed to your custom font, with a fallback to Comic Sans. When checked, if the string element width is the same, the fallback font of Comic Sans is still in use. If not, your font should be operational.
I rewrote the method of font load detection into a jQuery plugin designed to give the developer the ability to style elements based upon whether the font has been loaded or not. A fail safe timer has been added so the user isn’t left without content if the custom font fails to load. That’s just bad usability.
I have also added greater control over what happens during font loading and on fail with the inclusion of classes addition and removal. You can now do whatever you like to the font. I would only recommend modifying the fonts size, line spacing, etc to get your fall back font as close to the custom as possible so your layout stays intact, and users get an expected experience.
Here's a demo: http://patrickmarabeas.github.io/jQuery-FontSpy.js
Throw the following into a .js file and reference it.
(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);
Apply it to your project
.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'
});
});
Remove that FOUC!
.hideMe {
visibility: hidden !important;
}
.fontFail {
visibility: visible !important;
/* fall back font */
/* necessary styling so fallback font doesn't break your layout */
}
EDIT: FontAwesome compatibility removed as it didn't work properly and ran into issues with different versions. A hacky fix can be found here: https://github.com/patrickmarabeas/jQuery-FontFaceSpy.js/issues/1
Try WebFont Loader (github repo), developed by Google and Typekit.
This example first displays the text in the default serif font; then after the fonts have loaded it displays the text in the specified font. (This code reproduces Firefox's default behavior in all other modern browsers.)
Actually, there is a good way to understand all fonts begin to download or loaded completely or not and fall into some errors, but it is not just for a specific font, pay attention to the following code:
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
};
And also there is an option that returns Promise and it could handle with .then function:
document.fonts.ready
.then(() => console.log('do someting at the final with each status'))
Here is a different approach to the solutions from others.
I'm using FontAwesome 4.1.0 to build WebGL textures. That gave me the idea to use a tiny canvas to render a fa-square to, then check a pixel in that canvas to test whether it has loaded:
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();
};
As it uses a canvas it requires a fairly modern browser, but it might work on IE8 as well with the polyfill.
Here's another way of knowing if a #font-face has already been loaded without having to use timers at all: utilize a "scroll" event to receive an instantaneous event when the size of a carefully crafted element is changed.
I wrote a blog post about how it's done and have published the library on Github.
Try something like
$(window).bind("load", function() {
$('#text').addClass('shown');
});
and then do
#text {visibility: hidden;}
#text.shown {visibility: visible;}
The load event should fire after the fonts are loaded.
alternatively, you could add font-display: block to your #font-face declaration.
this instructs browsers to render the fallback font as invisible until your font is loaded, no need for display: none or any javascript load font detection
Solution for Typescript, Angular.
If you are working with Angular, you can use this module in order to do a font check.
// 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);
}
Also, some fonts are extremely heavy. Therefore, you can add a loading screen while the font is loading and remove the loading screen when the font is loaded. I believe this is a better approach rather than changing your CSS class to display: none, merely because it might take 3-4+ seconds to download some fonts if the user has slow internet.
This is an alternate approach that will at least ensure that font-awesome is loaded, NOT a complete solution to the OP. Original code found in the wordpress forums here https://wordpress.stackexchange.com/a/165358/40636.
It's agnostic and will work with any font style resource like font-awesome where a font-family can be checked. With a little more thought I bet this could be applied to much more...
<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>
Use the below code:
<!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>
Can check many fonts:
setTimeout(function(){alert(IsLoadedFonts('font1','font2','font3'));},100);
The below code works in opera only but is easy:
if(!document.defaultView.getComputedStyle(document.getElementById('mydiv'))['fontFamily'].match(/myfont/i))
alert("font do not loaded ");
I have a clock on my website written in javascript which I got from the internet and modified it slightly to fit my needs better and it looks great on firefox using a mac, but when I use it in other browsers on a PC or Mac it looks terrible and I have no idea how to change it, I'm fairly new to javascript. The code i'm using is below:
var alternate=0
var standardbrowser=!document.all&&!document.getElementById
if (standardbrowser)
document.write('')
function show(){
if (!standardbrowser)
var clockobj=document.getElementById? document.getElementById("digitalclock") : document.all.digitalclock
var Digital=new Date()
var hours=Digital.getHours()
var minutes=Digital.getMinutes()
var dn="AM"
if (hours==12) dn="PM"
if (hours>12){
dn="PM"
}
if (hours==0) hours=0
if (hours.toString().length==1)
hours="0"+hours
if (minutes<=9)
minutes="0"+minutes
if (standardbrowser){
if (alternate==0)
document.tick.tock.value=hours+" : "+minutes+" "+dn
else
document.tick.tock.value=hours+" "+minutes+" "+dn
}
else{
if (alternate==0)
clockobj.innerHTML=hours+" : "+minutes
else
clockobj.innerHTML=hours+" : "+minutes
}
alternate=(alternate==0)? 1 : 0
setTimeout("show()",1000)
}
window.onload=show
I am looking to be able to set the font and size of the clock to be uniform across most browsers if not all, i'm not too bothered about IE because to site is terrible in ie anyway and will get round to sorting that out in the future.
You can use CSS to do this. Your clock is being displayed in a container with an ID of digitalclock. That means you can define style rules in an external stylesheet, inline or in the <head> of your .html file:
#digitalclock {
font-size: 1em;
font-family: arial, helvetica, sans-serif;
font-weight: normal;
color: red;
/* and whatever other rules you want */
}
why don't you just style the containing html element (#digitalclock) via css?