I'm trying to include a custom font in my React app (made with create-react-app). It seems to be somewhat working but only after 2-3 second after loading the page. Until then, the text appears to use the browser's default font (like Times New Roman), and then swaps to the custom font after a few seconds. Can someone please explain to me why this is happening and what I need to do to fix this?
I'm importing the font into my top-level App.js file like so:
import './fonts/tarrgetital.ttf';
import './App.scss';
And have it declared in my App.scss file like so:
#font-face {
font-family: 'tarrgetital';
src: local('tarrgetital'), url(./fonts/tarrgetital.ttf) format('truetype');
}
h2 {
font-family: tarrgetital;
}
The delay in loading the web fonts is an expected behaviour issue and it's happening because the browser load the fonts when it detects a DOM element with a CSS selector that matches the font-face rule and that happens when then HTML file and all the CSS files have been downloaded on the client. It's a lazy loading mechanism. There are some solutions to improve this behavior:
Use optimized web font file:
For better performance, you can swap your TTF font file in the
font-face with the woff and woff2 file formats. these formats are
compressed in gzip thus reducing the file size and initial
downloading time on the client. If those formats are not available
you can use one of many online tools to convert the font file (google
TTF to woff2).
Webpack Preload:
In webpack 4.6.0+ you can preload modules. this uses
the preload hint in HTML link tags (<link rel="preload">). it will tell the browser to preload the resource before downloading the rest of the resources. To use this option replace import './fonts/tarrgetital.ttf'; with import(/* webpackPreload: true */ './fonts/tarrgetital.ttf');
More on webpack preload here: https://webpack.js.org/guides/code-splitting/#prefetchingpreloading-modules and more info on HTML preload hint here: https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content
One alternative is to use webfontloader. It was co-developed by Google and Typekit.
npm i webfontloader
In your App.js file add this one. Note: You still have to maintain your font face declarations at your css file.
import WebFont from 'webfontloader';
WebFont.load({
custom: {
families: ['tarrgetital'],
},
});
I use also font-face on index.css file
#font-face {
font-family: "Avenir";
src: local("Avenir"),
url("assets/fonts/AvenirNextLTPro-Regular.ttf") format("truetype");
font-weight: normal;
font-style: normal;
}
<link rel="stylesheet" href="../src/index.css" />
Then I imported index.css file into index.html, this worked for me.
Use document.fonts.load with useEffect
import React, { useEffect, useState } from 'react';
const MyComponent = () => {
const [loading, setLoading] = useState(true);
useEffect( ()=> {
document.fonts.load("12px Font-Name").then( () => { setLoading(false) } );
}, [])
return (
<React.Fragment>
{ loading
? <div> Loading... </div>
: <main> Rest of Elements </main>
}
</React.Fragment>
);
};
export default MyComponent;
Related
What does not work
I am trying to add some custom local fonts into my Electron React App, but i would like to do it without installing the fonts on my computer.
Current partial solution
The only way, which works for me, it is to install the fonts on my computer, but i would like to find a better solution.
I placed my fonts files into:
assets/fonts/
And i tried to use it in my scss file located in:
src/renderer/scss/commons/_fonts.scss
In this way:
#font-face {
font-family: 'Bariol Regular';
font-style: normal;
font-weight: normal;
src: local('Bariol Regular'),
url('/assets/fonts/Bariol-Regular.ttf') format('ttf');
}
These are my current Electron versions
"electron": "^15.1.0",
"electron-builder": "^22.11.7",
"electron-devtools-installer": "^3.2.0",
"electron-notarize": "^1.1.1",
"electron-rebuild": "^3.2.3",
How html has been loaded into electron:
new HtmlWebpackPlugin({
filename: path.join('index.html'),
template: path.join(webpackPaths.srcRendererPath, 'index.ejs'),
minify: {
collapseWhitespace: true,
removeAttributeQuotes: true,
removeComments: true,
},
isBrowser: false,
env: process.env.NODE_ENV,
isDevelopment: process.env.NODE_ENV !== 'production',
nodeModules: webpackPaths.appNodeModulesPath,
}),
The React App component has been mounted into the index.ejs file on the
<div id="root"></div>
And the scss file which contains the fonts rule, has been imported into the App.tsx file.
import './App.global.scss';
I would be grateful if someone could help me.
And i hope this could help someone else.
Thank you!
It's hard to tell how similar our setup is, but hopefully this helps someone.
My issue was putting the fonts in my public folder when they're supposed to be under src.
I made a fonts folder under src, then I declared the font in a css file. e.g:
/* src/index.css */
#font-face {
font-family: 'KleeOne';
src: url('./fonts/KleeOne-SemiBold.ttf');
}
After that, I imported the css in my index.js and it worked:
/* src/index.js */
import './index.css';
I'm using Workbox(V5) and in my workbox-config.js I precached the fonts (.woff and .woff2 formats) that are needed for the 3rd-party CSS styles that I'm using, by specifying this for the globPatterns property:
// workbox-config.js
module.exports = {
globDirectory: './',
globPatterns: [
'**/*.{html,ico,woff,woff2}',
],
globIgnores: [
'node_modules/**/*',
'{.,_}*/**/*',
'**/*.{md,txt}',
'Gemfile*',
'package*',
],
additionalManifestEntries: [
{
url: './manifest.webmanifest',
revision: null, // I have also precached my manifest file like this. Is it the best practice?
},
],
swDest: './sw.js',
sourcemap: false,
};
Now in the .css file of the 3rd-party, I can see that the needed fonts are being used with the #font-face rule that includes a query parameter in its URL value:
#font-face {
font-family: "bootstrap-icons";
src: url("./fonts/bootstrap-icons.woff?4601c71fb26c9277391ec80789bfde9c") format("woff"),
url("./fonts/bootstrap-icons.woff2?4601c71fb26c9277391ec80789bfde9c") format("woff2");
}
Well, if I remove the generated hash that has been added to the URL, when I run my PWA offline, the precached fonts show up just fine... But when the styles are calling the fonts with the hash, the precached fonts won't show up!
I have also tried to precache the fonts in my HTML file's head tag and the do runtimeCaching for the .woff and .woff2 formats instead of precaching them by the globPatterns property, but still no luck!
<link rel="preload" as="font" href="./assets/styles/vendor/fonts/bootstrap-icons.woff" type="font/woff2" crossorigin="anonymous">
<link rel="preload" as="font" href="./assets/styles/vendor/fonts/bootstrap-icons.woff2" type="font/woff2" crossorigin="anonymous">
So I was wondering how can we fix this problem?
Thanks a heap,
Ali
You can use the ignoreURLParametersMatching configuration option when generating your service worker to tell workbox-precaching that certain URL parameters can be ignored when checking the cache for a match.
The parameter takes an array of RegExps, and the default is [/^utm_/, /^fbclid$/], which matches some common analytics tracking parameters.
In your particular case, it sounds like the values you want to ignore are all 32 hex characters, so the following configuration should help:
// workbox-config.js
module.exports = {
ignoreURLParametersMatching: [/^[0-9a-f]{32}$/],
// ...other options go here...
};
I'm trying to add a Google Font (Mukta Malar) in my Gatsby site.
I've seen many articles on adding Google fonts to a Gatsby site and most of them seem to use this plugin: gatsby-plugin-prefetch-google-fonts.
I've used the above plugin in my site by adding it in the gatsby-config.js file as:
plugins: [
{
resolve: `gatsby-plugin-prefetch-google-fonts`,
options: {
fonts: [
{
family: `Mukta Malar`
},
],
},
}
]
and added the font family to my css file as well:
* {
font-family: "Mukta Malar", sans-serif;
}
But the Google font is not applying to the site. Is there a hidden step that I'm missing in my code?
This plugin seems to be no longer maintained and it's part of escalade monorepo (which throws a 404 error), last commit in the core from 1 year ago.
I would suggest gatsby-plugin-google-fonts that allows you to display: swap your fonts without affecting your performance. In your case:
{
resolve: `gatsby-plugin-google-fonts`,
options: {
fonts: [
`mukta malar`
],
display: 'swap'
}
}
Google fonts are available on npmjs.org with the name typeface-XXXXXX representing the name of the font family on the Google fonts website.
If I want to add the Poppins font on my Web site, I just need to add it on the package.json file:
yarn add typeface-poppins
Then in my site, i can use require("typeface-poppin") to use the font:
import React from "react"
import { Link } from "gatsby"
import Layout from "../components/layout"
import Image from "../components/image"
import SEO from "../components/seo"
require('typeface-poppins')
const IndexPage = () => (
<Layout>
<SEO title="Home" />
<h1 style={{fontFamily: "Poppins"}}>Hi people</h1>
<p>Welcome to your new Gatsby site.</p>
<p>Now go build something great.</p>
<div style={{ maxWidth: `300px`, marginBottom: `1.45rem` }}>
<Image />
</div>
<Link to="/page-2/">Go to page 2</Link> <br />
<Link to="/using-typescript/">Go to "Using TypeScript"</Link>
</Layout>
)
export default IndexPage
As other mentioned, include the fonts in your Gatsby project, this will be way faster!
Gatsby has a really great write up about this on their page actually.
https://www.gatsbyjs.com/docs/how-to/styling/using-web-fonts/
Here is a an example:
First you install the font using npm or yarn:
yarn add #fontsource/mukta-malar // npm install
#fontsource/mukta-malar
Then in your layoutfile for the page, import the font like this:
import "#fontsource/mukta-malar"
You the reference the font in css like you would do it with any google font:
font-family: 'Mukta Malar', sans-serif;
If you only need a few specific weights or variants you can also import only parts of the package like this:
import "#fontsource/mukta-malar/500.css"
this will only load weight 500 aka "medium" weight.
I am using Next.js with Typescript. The margin of the body is default 8px and I want to get it to 0px. When I try to add an external style sheet to my index.tsx file it throws an error that you can only add external stylesheet to _app.tsx. However, even when I try to import in my _app.tsx, it doesn't change the global style of the body. I am using Emotion css for the styling part. Is there a different way to change the style of the body in the index file using global style? Here is my index.tsx code and I have tried adding the global styles using Emotion CSS as well but it doesn't work.
class Index extends React.Component {
render() {
return (
<div className='body'>
<Container>
<style jsx global>{`
.body:global() {
margin: 0px;
}
`}</style>
<NavBar />
</Container>
</div>
);
}
}
You need some global styles (<style jsx global>) to style the body element or provide css resets.
Example:
import Link from "next/link";
export default () => (
<div>
<style jsx global>{`
body {
background-color: red;
}
`}</style>
Hello, One!
<Link href="/two">
<a>Go to two</a>
</Link>
</div>
);
Code Sandbox
You can have global styles using emotion with Next.js
In your _app.tsx file, you must to
import { Global, css } from '#emotion/core'
return (
<>
<Global styles={css` /* styles */ `}/>
<Component {...pageProps} />
</>
You can see how to implement it, here
https://github.com/pabloobandodev/social-media/blob/master/pages/_app.tsx
According to the official docs:
Global CSS cannot be used in files other than your Custom <App> due to its side-effects and ordering problems.
Possible Ways to Fix It
Relocate all Global CSS imports to your pages/_app.js file.
How to do this in your case?
Well, the best way is to use a CSS base, lets take normalize.css for example.
Run yarn add normalize.css or npm i normalize.css, depending on whichever you are using.
Add import 'normalize.css'; in each of the page you want to use the base on. Official Docs.
Well this could seem redundant if you want to use the base in all of your pages. If so, you can, alternatively, create a file page/_app.tsx (any of the extension .js,.jsx,.ts,.tsx will work) and put this in it:
import 'normalize.css';
export { default } from 'next/app';
Note : If your app is running and you just added a custom App, you'll need to restart the development server. Only required if pages/_app.tsx didn't exist before.
No need to worry about other caveats mentioned in the docs as we are simply re-exporting App without any modification.
There are many CSS bases available choose any that seems best for you.
If you want to add custom global styles, then follow this:
Create a file styles/globals.css (.scss,.sass,etc. will also work if you have configured Next.js properly) and put your styles in that file.
Now add an import in pages/_app.tsx.
import '../styles/globals.css'; // change extension from `.css` to
// whatever you created above
export { default } from 'next/app';
If you have already created a module path alias for ../styles, then you might wanna change the styles import statement (probably to something like import '#styles/globals.css').
Also, if you are using less/sass/scss and want to use a base at the same time along with your custom global styles you simply need to use an import statement in your stylesheet (no need to import the base in _app.tsx if imported in the global stylesheet). An example:
// file: styles/globals.scss
#import '../node_modules/normalize.css/normalize.css';
// your styles...
body {
color: red;
}
// file: pages/_app.tsx
import '#styles/globals.scss';
export { default } from 'next/app';
Moreover, in your case it has not worked most probably because you were styling .body instead of body. It is likely that margin was present in the body, not your div.body.
This is how your _app.js, _app.tsx should look like; styles.css may have your CSS to reset the default browser properties, you can try adding other stylesheets here.
import '../styles/styles.css'
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />
}
I'm currently working with rails and reactjs. I'm having difficulties using css in my reactjs files. It seems like every time i try to use it, no change is being applied at all. In my App.jsx file I have this:
import React from "react";
import styles from "./styles.css";
export default class Register extends React.Component {
render() {
return (
<div className={styles.container}>
<h1> this text should appear to the right </h1>
</div>
);
}
}
And in my styles.css file I have this:
.container {
width:40%;
text-align:right;
}
For the record I am using webpack. Can anyone help me understand why the css isn't having any effect on my jsx components. I've looked all over for help but was unable to put the pieces together.
If it matters, this is how my "config/webpack/development.js" file looks like:
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
const environment = require('./environment')
module.exports = environment.toWebpackConfig()
It depends on the webpack loader settings. If you are using css-loader as configured in react-scripts (as of 1.1.5), then the classNames are loaded using {modules: false} option, i.e. global styles, which can be referenced as strings in JSX code:
import "./styles.css";
... className="container" ...
Or you can load local styles using following CSS-file syntax:
:local .container {...
Or edit your webpack.config.js appropriately (see https://github.com/webpack-contrib/css-loader#scope for the official documentation of various options).
seems like you didn't enable an option { modules: true } for css-loader in webpack config
take a look
webpack-contrib/sass-loader#206
https://github.com/webpack-contrib/css-loader#options
Taken from: https://github.com/facebook/create-react-app/issues/1350