Reputation: 2202
Should we include the fonts in index.html file with rel="preload"
like the below code or can we configure this in Angular CLI to preload all the fonts required?
Please suggest me a better solution as I can see it takes multi-second page load time suggested in Google Analysis.
<link rel="preload" href="./assets/fonts/Lato/Lato-Semibold.woff2" as="font" crossorigin>
<link rel="preload" href="./assets/fonts/Lato/Lato-Black.woff2" as="font" crossorigin>
<link rel="preload" href="./assets/fonts/Lato/Lato-Bold.woff2" as="font" crossorigin>
<link rel="preload" href="./assets/fonts/Lato/Lato-Heavy.woff2" as="font" crossorigin>
<link rel="preload" href="./assets/fonts/Lato/Lato-Medium.woff2" as="font" crossorigin>
<link rel="preload" href="./assets/fonts/Lato/Lato-Regular.woff2" as="font" crossorigin>
Upvotes: 20
Views: 8192
Reputation: 281
The best option you can try by using APP_INITIALIZER
like this:
Create a FontProvider:
export const FontProvider = () => {
const fonts = [
{
family: "Lato Regular",
src: "./assets/fonts/Lato/Lato-Regular.woff2",
options: {
weight: '400',
style: 'normal'
}
},
{
family: "Lato Semibold",
src: "./assets/fonts/Lato/Lato-Semibold.woff2",
options: {
weight: '600',
style: 'normal'
}
}
];
for (const {family, src, options} of fonts) {
const font = new FontFace(family, src, options);
font.load()
.then(() => document.fonts.add(font))
.catch(err => console.log(err))
}
}
Now, add this FontProvider to you app.module.ts
file :
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AppComponent } from './app.component';
import { BrowserModule } from '@angular/platform-browser';
import { FontProvider } from './font.provider.ts'
@NgModule({
imports: [CommonModule, BrowserModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [
{
provide: APP_INITIALIZER,
useFactory: FontProvider,
multi: true
}
]
})
export class AppModule {}
This will work 100% and let me know if you need some other suggestion or help.
Upvotes: 1
Reputation: 9052
Only way I could come up with to force the browser to pre-download the font files, is to actually use the font.
Create a font-preload.css
file ie. /assets/fonts/Lato/font-preload.css
:
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(Lato-Regular.woff2) format('woff2');
}
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(Lato-Medium.woff2) format('woff2');
}
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(Lato-Semibold.woff2) format('woff2');
}
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(Lato-Bold.woff2) format('woff2');
}
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 800;
font-display: swap;
src: url(Lato-Heavy.woff2) format('woff2');
}
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 900;
font-display: swap;
src: url(Lato-Black.woff2) format('woff2');
}
/* font pre-load class with off-screen invisible text */
.f-pl {
position: absolute;
top: -14000px;
left: -14000px;
font-size: 0.001px;
width: 0;
height: 0;
color: transparent
}
/* For each font, create a class with the font-family and its weight
which matches the font file to be downloaded */
.f-pl.lato-regular {
font-family: 'Lato';
font-weight: 400;
}
.f-pl.lato-medium {
font-family: 'Lato';
font-weight: 500;
}
.f-pl.lato-semibold {
font-family: 'Lato';
font-weight: 600;
}
.f-pl.lato-bold {
font-family: 'Lato';
font-weight: 700;
}
.f-pl.lato-heavy {
font-family: 'Lato';
font-weight: 800;
}
.f-pl.lato-black {
font-family: 'Lato';
font-weight: 900;
}
Include the css stylesheet in the end of the <head>
tag and also elements with the f-pl
class for each font in the <body>
tag:
<link href="assets/fonts/Lato/font-preload.css" rel="stylesheet">
</head>
<body>
<!-- use the fonts so the browser downloads the font files -->
<a class="f-pl lato-regular">1</a>
<a class="f-pl lato-medium">1</a>
<a class="f-pl lato-semibold">1</a>
<a class="f-pl lato-bold">1</a>
<a class="f-pl lato-heavy">1</a>
<a class="f-pl lato-black">1</a>
<app-root></app-root>
The .f-pl
class will move the tiny transparent text off-screen and out of view with its position: absolute;
and top: -14000px; left: -14000px;
.
If you have fonts with unicode-range:
for specific unicode ranges, just create a class for that font + weight then instead of 1
as the character, use a character in that specific unicode range.
This also works for Material Icons/Symbols for instance:
.f-pl.material-symbols-outlined {
font-family: 'Material Symbols Outlined'
}
.f-pl.material-symbols-sharp {
font-family: 'Material Symbols Sharp'
}
.f-pl.material-symbols-rounded {
font-family: 'Material Symbols Rounded'
}
Then in the <body>
tag:
<a class="f-pl material-symbols-outlined">1</a>
<a class="f-pl material-symbols-sharp">1</a>
<a class="f-pl material-symbols-rounded">1</a>
Upvotes: 0
Reputation: 1
Including multiple preload links for each font file can bloat your html file and make it harder to manage.
1. You can create a service in angular to handle font preloading. This will allow flexibility.
2. You can also configure your angular.json file
"assets": [
"src/favicon.ico",
"src/assets",
{
"glob": "**/*",
"input": "node_modules/@fortawesome/fontawesome-free/webfonts",
"output": "/webfonts/"
}
]
3. If the fonts you have are not part of application standard assets, you can use a service as
In service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class FontPreloadingService {
preloadFonts(fontUrls: string[]) {
fontUrls.forEach((url) => {
const link = document.createElement('link');
link.rel = 'preload';
link.as = 'font';
link.href = url;
link.crossOrigin = 'anonymous';
document.head.appendChild(link);
});
}
}
Preload the fonts in your component
In app.ts
import { Component, OnInit } from '@angular/core';
import { FontPreloadingService } from './font-preloading.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
constructor(private fontPreloadingService: FontPreloadingService) {}
ngOnInit() {
const fontUrls = [
'./assets/fonts/Lato/Lato-Semibold.woff2',
'./assets/fonts/Lato/Lato-Black.woff2',
// Add other font URLs as needed
];
this.fontPreloadingService.preloadFonts(fontUrls);
}
}
Upvotes: 0
Reputation: 1
For this implementation in angular, you should use third-party dependency to load the fonts.,Find centralized, trusted content and collaborate around the technologies you use most.,Connect and share knowledge within a single location that is structured and easy to search. After that load your custom font like this
WebFont.load({
custom: {
families: [""
Lato "]
}
});
Upvotes: -2
Reputation: 71
Example::
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="preload" as="style" href="https://fonts.googleapis.com/css2family=Merriweather&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2family=Merriweather&display=swap" media="print" onload="this.media='all'" />
<noscript>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2family=Merriweather&display=swap" />
</noscript>
For your reference : Link to Harry Roberts explanation on fonts loading
Upvotes: 0
Reputation: 797
For this implementation in angular, you should use third-party dependency to load the fonts.
use webfontloader
npm i webfontloader
After that load your custom font like this
WebFont.load({
custom: {
families: [""Lato"]
}
});
Upvotes: -2