Webfont performance - webfontloader vs preload - javascript

I am currently thinking about using webfonts from Google, but I have still no idea which way to do it, because there are many different opinions on the internet.
I have following options:
Webfontloader by typekit and google
rel attribute preload
When checking the performance of both on a slow 3G network, I get similar results regarding the performance. The downside of the webfontloader is the FOUT (Flash of unstyled text). Is there a way to get around that? The downside of preload is that its not supported by many browsers. Is there a fallback? I couldn't find one. Maybe you have another entirely different way.
Thanks for your help,
Nuru

I've always found the most performant way to load webfonts is as local files on your site. Just use .woff and .woff2 files because these will cover you back to IE8 unless there is some special reason to use an .otf font and then just have some good fallback system fonts. The problem with using external font libraries is that the only performance benefit from them is if the visitor has the same font from the same resource in their cached files from viewing said font on a different site. There are so many fonts on sites like Googlefonts and Typekit this isn't as likely as you think, and even then I've still not seen any improvement in performance. You can download the font files from Google (or of course from many other sources) and then convert them to woff and woff2 here:
https://onlinefontconverter.com/
Then load them into your site at the top of your site's CSS file. The example below is if I was using a font called geo-light and the font files are inside a font folder in the root of my site
#font-face {font-family: 'geo-light';
src: url('fonts/geo-light.woff2') format('woff2'), url('fonts/geo-light.woff') format('woff');
font-weight: normal;
font-style: normal;
}
You must set the font-weight and font-style to normal in the #font-face declaration and then add this again in terms of how you want the actual text styled in your elements. This will prevent rendering discrepancies across different browsers. If you download the actual different font-weights as different files you'll always need to set these to normal. Doing it this way will also prevent the dreaded FOUT.
h1, h2, h3 {
font-family: 'geo-light', sans-serif;
font-weight: normal;
font-style: normal;
}

Related

Performance of Font Awesome

A web development company develops a website for me, which uses 12 icons from Font Awesome 5.15.3. They use SVG with JavaScript. After using Google PageSpeed Insights, I find the Font Awesome JavaScript becomes the performance bottleneck.
I then find "Performance & Font Awesome". But this does not provide much information on each method. I try to contact the support but get no responses by now. So I am trying to test with these methods by myself, such as SVG Sprites and individual SVG icons, meanwhile sharing my understanding of the pro and con of each method in performance.
Note: I will only consider the case that I host Font Awesome on my own server.
SVG with JavaScript: Based on my debug in Chrome DevTools, it seems that the javascript code is just find the patterns like and replace them with the corresponding svg icons. This will be time-consuming if the DOM tree of the whole page is large. Also why bother to let the JavaScript to do the task if one can just insert SVG icon to the location manually? I guess there are 3 reasons:
a. <i class="fas fa-camera"></i> is short(29 characters only) and more convenient to use than using an individual SVG Icon(normally 500 bytes) or a SVG Sprites(3 lines with total 88 characters).
b. It will not bloat the source HTML page too much.
c. It is good only if the same icon is used for many times, like below:
Web Fonts with CSS
In this method, one needs to include the Font Awesome font files with #font-face rule. And the download of the large Font Awesome font files will become the bottleneck of the performance. As far as I know, if I only use 16 icons from 1000 icons, there are no way to create a new font file containing only the 16 icons from the existing one.
SVG Sprites: This method seems to be great for my case. I can create a small svg file containing only the 16 icons I need. Then use the following way to include it in the HTML page:
<svg>
<use xlink:href="fa-brands.svg#facebook"></use>
</svg>
Though it requires 3 lines than 1 line(SVG with JS). It is still short, even if the icon is used for multiple times. I guess the disadvantage of this method is one plan to use many icons, for example, 100 icons. In such a case, the svg file will be large and become the performance bottleneck when downloading it.
Another disadvantage may be due to that to search in the SVG Sprite file, it will take some time, since the individual icons in SVG Sprite file is not indexed in any way.
Individual SVG icons: Embedding the SVG icon data to the HTML source will be the most efficient way in performance. But each SVG icon file will be about 500 bytes to 3KB, which will bloat the HTML file greatly. Also it is not good if the icon will be used in the page for many times, as in such a case, the HTML source will become huge.
Also "the browser cannot cache inline SVG as it would cache regular image assets, so pages that include the image will not load faster after the first page containing the image is loaded." based on https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web
SVG + CSS: THis method is not mentioned in Font Awesome, but are widely used. See https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web for different ways to add SVG to webpage, including SVG + CSS.
Please kindly advise if my understandings are correct or not. THank you very much!
Update:
I find one interesting comparison on their site: Web Fonts vs SVG
Update 2
I add another popular method which uses SVG + CSS
From my own personal experience I can tell you that I prefer to use the 12 icons approach VS anything else. Web fonts were great solution when not all major browsers were well performing svg standard. But today it's nonsense to use a bloating icon font when you just use 12 icons from there. If you want to be able to measure the impact of leaving the font and using the svg icons instead go and take a look to the performance and speed of my own web site here https://www.simbiosis-dg-apps.com. I tell you that except for the 2 pictures of myself and my partner every thing else that you will see is svg. Sometimes embedded into the html and most of the time called through the img tag. For the icons I use a similar method like the one that is used to set icons from an icon font but using my own css system. If want a better picture see this answer How to Replace the Web Font with SVG icon in CSS(Font Awesome)?

How to get the rendered font in JavaScript?

Google Chrome displays the rendered font in the DevTools.
For example, given:
font-family: Montserrat, Helvetica, sans-serif;
and the Montserrat font is missing/disabled, Chrome tells us that Helvetica is being rendered:
Is there a way to get the rendered font in JavaScript? (even if it just works in Chrome)
Notes:
This solution suggests getComputedStyle(...).fontFamily, but it returns the CSS declaration "Montserrat, Helvetica, sans-serif", not the actual rendered font.
This solution uses puppeteer, but I couldn't figure out how to achieve the same purely in DevTools (without puppeteer).
It is still not possible to access this information from Web-APIs.
There is an ongoing discussion in the Houdini group about including a font-metrics API, that is supposed to include something like that, but it's still not even proposed as a spec draft and there will be a lot of burden on the road.
What font(s) are being used? This is complicated because multiple fonts can be used per paragraph, per line, per word, and even per glyph. The fonts should be exposed in the form of handles with complete font information, and (for web fonts) a handle to the raw font data. dbaron & eae are going to own this area and propose an API.
Indeed, one could have one font for the glyph ̂ (U+0302), and another one for the glyph a (U+0061) which would make the combined glyph â would actually use two different fonts.
Current discussions seem to point to a Font interface available from document.measureElement and document.measureText methods. This interface would expose two properties: a DOMString name, and a number glyphsRendered.
However, once again these are still discussion and still not yet proposed as drafts, a lot of discussion is still to be made and I wouldn't hold my breath waiting for it to be implemented anywhere any time soon.
Now, there are hacks, like numerous other Q/A already told don't stick to the accepted answer there, implying looking at the size of the rendering for the simplest, and looking at the rendered pixels for the more advanced ones, but being hacks, they won't work in every cases.
For instance, I could have a custom font on my system that would render only some characters borrowed from a well-known font, no such hack would be able to tell if the browser did fallback to that font or the actual well-known one.
The only way to know for sure is to keep the control and use web-fonts.
Since no one had suggested it yet, there would be one more way to find out which font is rendered.
The snippet below gets the font-family CSS definition in use for the element (or of course you can hardcode the font-family names if you want) and checks in order, whether the font family is loaded and returns the name of the first loaded font family.
Since the font-family CSS property specifies a prioritized list of one or more font family names, the first available font is very likely also the rendered font.
Snippet uses the CSS Font Loading API, which is well supported (but not in IE of course)
https://developer.mozilla.org/en-US/docs/Web/API/CSS_Font_Loading_API
For example, let's imagine that the CSS would be:
.body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI Adjusted", "Segoe UI", "Liberation Sans", sans-serif;
}
Snippet
const getRenderedFontFamilyName = ( element ) => {
// Font families set in CSS for the element
const fontFamilies = window.getComputedStyle( element, null ).getPropertyValue( "font-family" );
// const hardcodedFamilies = '-apple-system, BlinkMacSystemFont, "Segoe UI Adjusted", "Segoe UI", "Liberation Sans", sans-serif';
// Remove the " sign from names (font families with spaces in their names) and split names to the array
const fontFamiliesArr = fontFamilies.replaceAll('"', "").split(", ");
// Find the first loaded font from the array
return fontFamiliesArr.find( e => document.fonts.check( `12px ${e}`) );
}
Example how to get rendered font-family of StackOverflow body:
getRenderedFontFamilyName(document.querySelector('body'));

How to avoid page jump and FOUT during font loading and page loading

I am developing a website and I can't host the font. So it has to be loaded from an external resource. However, it loads slowly and because the font is not a standard font, it causes massive page jump on loading. The browser default font always loads first and when the font changes everything moves around and the entire scroll height of the page changes. And it's a big problem because one of the forms on the page shifts right at the point where you'd be starting to select a field and you end up selecting the wrong one when it jumps.
I have tried using font pre-loading just to find out that there is a massive lack of browser support. And even with testing on google chrome which is supposed to support it, it seems to fail and resort to the browser default font once in a while. ( link rel preload...)
Currently, I'm using a messy javascript solution that basically hides the page until the font loads and then uses a timeout to allow the browser time to render with the new font before making the page visible again. And then it uses another timeout that's a bit longer in case the font doesn't load at all to show the page as a backup.
It feels really unprofessional. I feel like it's causing an additional delay on the users end which shouldn't be necessary. There has to be a better way to go about this but I'm not finding one. I can't set a fixed height for the elements because some of the content and questions in the forms is user generated. I'm listing the terrible inline code which I'm currently using.
document.body.style.visibility="hidden";
//the link element that loads the font currently has an id
var font=document.getElementById('font');
font.onload=function(){
var timeout=self.setTimeout(function({
document.body.style.visibility="visible";
},100);
}
var fallback=self.setTimeout(function(){
document.body.style.visibility="visible";
},1000);
I don't mind the results I'm getting with my current solution. But I feel like there definitely has to be a better way of going about this?
I would agree with your assessment that the delay on the client side is unideal and unnecessary. Case studies by Google and the BBC have found that every second of load time can increase the bounce rate (the number of people who leave the site after visiting just one page) by as much as 10-20%.
One strategy you could use to reduce load time is narrowing the character set you load. If you're hosting the fonts yourself, segmenting the font and using a unicode-range value in your #font-face definition would be the best way to accomplish this. Some providers like Google Fonts allow you to do this with query string parameters, as well.
This can significantly reduce the number of unused, unneeded glyphs (e.g., foreign and special characters) that the client has to load.
As for reducing FOUT, one thing you could try is downloading the roman (regular) style to your machine, encoding it as base-64, and then embedding it directly into your page styling, e.g.,
#font-face {
font-family: MyFontName;
src: url('data:application/x-font-woff;charset=utf-8;base64, <font data> ') format('woff');
font-weight: normal;
font-style: normal;
}
Because the normal font style is directly integrated into your HTML/CSS contents, its load time is insignificant. The great part about this is that when browsers receive only a regular style, they automatically generate their own bold and italic versions. You can take advantage of this behavior and use it as a stand-in for your proper styles until they load.
Also, if you're not doing so already, take a look at different web font formats like WOFF2, and compression methods like Brotli (which WOFF2 uses).
Here are a couple of resources that cover these and other methods in detail:
A Comprehensive Guide to Font Loading
Strategies
FOUT, FOIT, FOFT
If you are using Google fonts make sure you don't have the &display=swap query param set.
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght#100;200;300;400;500;700;900&display=swap" rel="stylesheet">
This instructs the browser to do a font jump in every case.
Jumping fonts is not good, especially above the fold.
Remove the &display=swap and the jump will stop.

Why do designers use sIFR if they can use #font-face?

Why do designers use sIFR if they can use #font-face ?
What is wrong with #font-face ?
#font-face {
font-family: "Hacen Tehran_eot";
src: url('Hacen Tehran.eot');
}
#font-face {
font-family: "Hacen Tehran_ttf";
src: url('Hacen Tehran.ttf');
}
p {
font-family:"Hacen Tehran_eot", "Hacen Tehran_ttf", sans-serif;
font-size:40px;
}
What is wrong with #font-face ?
It's new, or at least compatible browser support for it is new.
Until very recently, the only browser to support it was IE, and then only with the EOT font format, which could only be generated by the complicated and unpopular WEFT application.
There are still format problems today. Although WOFF is the clear future winner, we've still got some recent browsers that need TTF/OTF instead, plus iPhone and its bizarre SVG fonts, and of course plenty of IE<9 browsers that want EOT.
Combine this with the issue of finding fonts whose licences actually allowed them to be embedded in a web page, and #font-face was a non-starter. The licence situation has got much better recently, with plenty of good-quality fonts available for real web embedding.
But still, chances are if you've already picked a font, especially from one of the major foundries who are still dragging their heels, it's not going to be possible to license it. Vector-based replacement techniques like sIFR and Cufon are more like the regular embedding that traditional licences often allow, and image-based replacement techniques don't need an embedding licence at all.
There are a few possible reasons:
You can embed many more fonts into Flash than you can currently get a licensed font-face compatible version of.
Even when you can get a licensed version it is often less expensive to use the font files you have that are compatible with Flash instead of buying new font-face versions.
Font-face versions of fonts are often licensed based on traffic instead of the flat rate designers are used to for desktop licensing. If you expect a site to get 10 Million page views per month its possible that the client might not want to pay the licensing for those fonts.
Some designers just don't know how to use font-face as well, but that is just a matter of education.
#font-face relies on the rendering engine of the browsers its text is appearing in so it may very well look aliased on Windows machines. This is true of Google Web Fonts and, I assume, of Typekit and similar services--this is why I continue to use sIFR. I've got a more expanded answer to this post's question here: What are cons to use Cufon? Is sIFR still good option? #font-face doesn't make the letters smooth like they look with cufon or sIFR
You cannot do complicated gradient effects such as horizontal colour scaling with sIFR whereas this can be quickly put together in a flash file.

How to detect which one of the defined font was used in a web page?

Suppose I have the following CSS rule in my page:
body {
font-family: Calibri, Trebuchet MS, Helvetica, sans-serif;
}
How could I detect which one of the defined fonts were used in the user's browser?
For people wondering why I want to do this is because the font I'm detecting contains glyphs that are not available in other fonts. If the user does not have the font, then I want it to display a link asking the user to download that font (so they can use my web application with the correct font).
Currently, I am displaying the download font link for all users. I want to only display this for people who do not have the correct font installed.
I've seen it done in a kind of iffy, but pretty reliable way. Basically, an element is set to use a specific font and a string is set to that element. If the font set for the element does not exist, it takes the font of the parent element. So, what they do is measure the width of the rendered string. If it matches what they expected for the desired font as opposed to the derived font, it's present. This won't work for monospaced fonts.
Here's where it came from:
Javascript/CSS Font Detector (ajaxian.com; 12 Mar 2007)
I wrote a simple JavaScript tool that you can use it to check if a font is installed or not.
It uses simple technique and should be correct most of the time.
jFont Checker on github
#pat Actually, Safari does not give the font used, Safari instead always returns the first font in the stack regardless of whether it is installed, at least in my experience.
font-family: "my fake font", helvetica, san-serif;
Assuming Helvetica is the one installed/used, you'll get:
"my fake font" in Safari (and I believe other webkit browsers).
"my fake font, helvetica, san-serif" in Gecko browsers and IE.
"helvetica" in Opera 9, though I read that they are changing this in Opera 10 to match
Gecko.
I took a pass at this problem and created Font Unstack, which tests each font in a stack and returns the first installed one only. It uses the trick that #MojoFilter mentions, but only returns the first one if multiple are installed. Though it does suffer from the weakness that #tlrobinson mentions (Windows will substitute Arial for Helvetica silently and report that Helvetica is installed), it otherwise works well.
A technique that works is to look at the computed style of the element. This is supported in Opera and Firefox (and I recon in safari, but haven't tested). IE (7 at least), provides a method to get a style, but it seems to be whatever was in the stylesheet, not the computed style. More details on quirksmode: Get Styles
Here's a simple function to grab the font used in an element:
/**
* Get the font used for a given element
* #argument {HTMLElement} the element to check font for
* #returns {string} The name of the used font or null if font could not be detected
*/
function getFontForElement(ele) {
if (ele.currentStyle) { // sort of, but not really, works in IE
return ele.currentStyle["fontFamily"];
} else if (document.defaultView) { // works in Opera and FF
return document.defaultView.getComputedStyle(ele,null).getPropertyValue("font-family");
} else {
return null;
}
}
If the CSS rule for this was:
#fonttester {
font-family: sans-serif, arial, helvetica;
}
Then it should return helvetica if that is installed, if not, arial, and lastly, the name of the system default sans-serif font. Note that the ordering of fonts in your CSS declaration is significant.
An interesting hack you could also try is to create lots of hidden elements with lots of different fonts to try to detect which fonts are installed on a machine. I'm sure someone could make a nifty font statistics gathering page with this technique.
A simplified form is:
function getFont() {
return document.getElementById('header').style.font;
}
If you need something more complete, check this out.
There is a simple solution - just use element.style.font:
function getUserBrowsersFont() {
var browserHeader = document.getElementById('header');
return browserHeader.style.font;
}
This function will exactly do what you want. On execution It will return the font type of the user/browser. Hope this will help.
Another solution would be to install the font automatically via #font-face which might negate the need for detection.
#font-face {
font-family: "Calibri";
src: url("http://www.yourwebsite.com/fonts/Calibri.eot");
src: local("Calibri"), url("http://www.yourwebsite.com/fonts/Calibri.ttf") format("truetype");
}
Of course it wouldn't solve any copyright issues, however you could always use a freeware font or even make your own font. You will need both .eot & .ttf files to work best.
Calibri is a font owned by Microsoft, and shouldn't be distributed for free. Also, requiring a user to download a specific font isn't very user-friendly.
I would suggest purchasing a license for the font and embedding it into your application.
I am using Fount. You just have to drag the Fount button to your bookmarks bar, click on it and then click on a specific text on the website. It will then show the font of that text.
https://fount.artequalswork.com/
You can use this website :
http://website-font-analyzer.com/
It does exactly what you want...
You can put Adobe Blank in the font-family after the font you want to see, and then any glyphs not in that font won't be rendered.
e.g.:
font-family: Arial, 'Adobe Blank';
As far as I'm aware there is no JS method to tell which glyphs in an element are being rendered by which font in the font stack for that element.
This is complicated by the fact that browsers have user settings for serif/sans-serif/monospace fonts and they also have their own hard-coded fall-back fonts that they will use if a glyph is not found in any of the fonts in a font stack. So browser may render some glyphs in a font that is not in the font stack or the user's browser font setting. Chrome Dev Tools will show you each rendered font for the glyphs in the selected element. So on your machine you can see what it's doing, but there's no way to tell what's happening on a user's machine.
It's also possible the user's system may play a part in this as e.g. Window does Font Substitution at the glyph level.
so...
For the glyphs you are interested in, you have no way of knowing whether they will be rendered by the user's browser/system fallback, even if they don't have the font you specify.
If you want to test it in JS you could render individual glyphs with a font-family including Adobe Blank and measure their width to see if it is zero, BUT you'd have to iterate thorough each glyph and each font you wanted to test, but although you can know the fonts in an elements font stack there is no way of knowing what fonts the user's browser is configured to use so for at least some of your users the list of fonts you iterate through will be incomplete. (It is also not future proof if new fonts come out and start getting used.)

Categories

Resources