Closed ooloth closed 6 years ago
Just use url()
inside the css where you import the font. This should tell webpack to also include this in the build.
I deleted my earlier replies that contained a few errors...
I added the following @font-face
declaration to src/layouts/font-face.css
(which I then imported into src/layouts/index.js
):
@font-face {
font-family: 'Font File';
src: url('..fonts/font-file.woff2') format('woff2'),
url('..fonts/font-file.woff') format('woff');
font-weight: normal;
font-style: normal;
}
This resolved the net::ERR_ABORTED
error in the console, but the font files are still not being copied to /public/
. Any idea why?
That looks very similar to the setup I have, which has been working OK. Are you missing a /
near the beginning of the url paths? e.g. change this:
url('..fonts/font-file.woff') format('woff')
to
url('../fonts/font-file.woff') format('woff')
Also I believe that files are not copied to the public/
directory if you're running Gatsby's development mode (gatsby develop
), that only happens in production mode (gatsby build
). You can check the Network tab of your browser's developer tools to confirm that the font files are loaded when running in development mode.
@m-allanson Apologies for the typo! I had the /
in my code, but missed it here.
Thanks for clarifying that files are not copied to public/
in development mode! I see in the Network tab that the font files are being loaded, so everything appears to be working properly.
Does it works with styled-components
?
I just tried the following code:
@font-face {
font-family: "RFRufo-Bold";
font-style: normal;
font-weight: normal;
src: url("../../etc/fonts/RFRufo-Bold.woff") format("woff"), url("../../etc/fonts/RFRufo-Bold.ttf") format("ttf");
}
Which load my font from /etc/foo/bar
, outside of the /public/
directory --> works on my computer because there is the /etc/ directory, but it wont be preset on the production server.
Shouldn't Gatsby / Webpack load this file into my public
dir?
Webpack file-loader doesn't work with styled components. Just traditional CSS.
@KyleAMathews Thanks for the confirmation. Could I declare my own file-loader
webpack rule?
Something like this:
config.loader("custom-fonts", {
test : /(fonts)\/(.*)\.(eot|svg|ttf|woff|woff2)$/i,
loader : "file-loader",
query : {
name: "fonts/[name].[ext]"
}
});
No — webpack has no way of knowing about styled components. Gatsby already has file-loader setup for fonts. It's just webpack doesn't see what you're declaring in styled components. Just copy the css to a fonts.css
and import it into your layouts/index.js
Another solution would be to make a JS import as:
import RufoBold from "../../etc/fonts/RFRufo-Bold.ttf";
But it's not really viable with multiple fonts and extensions... I will stick with one single CSS file for fonts declarations then.
Thanks for your answers.
After some discussions, we finally picked up the JS import solution in a dedicated file:
// shared/css/fonts.js
import RufoBlackTTF from "fonts/RFRufo-Black.ttf";
import RufoBlackWOFF from "fonts/RFRufo-Black.woff";
import RufoBoldTTF from "fonts/RFRufo-Bold.ttf";
import RufoBoldWOFF from "fonts/RFRufo-Bold.woff";
import RufoSemiBoldTTF from "fonts/RFRufo-SemiBold.ttf";
import RufoSemiBoldWOFF from "fonts/RFRufo-SemiBold.woff";
import RobotoRegularTTF from "fonts/Roboto-Regular.ttf";
import RobotoBoldTTF from "fonts/Roboto-Bold.ttf";
import RobotoMediumTTF from "fonts/Roboto-Medium.ttf";
export {
RufoBlackTTF,
RufoBlackWOFF,
RufoBoldTTF,
RufoBoldWOFF,
RufoSemiBoldTTF,
RufoSemiBoldWOFF,
RobotoRegularTTF,
RobotoBoldTTF,
RobotoMediumTTF
};
Then used from the @font-face
declaration:
// shared/css/globalStyles.js
import { createGlobalStyle } from "styled-components";
import fontFiles from "./fonts";
export default createGlobalStyle `
@font-face {
font-family: "Rufo-Black";
font-style: normal;
font-weight: normal;
src: local("Rufo Black"), local("Rufo-Black"), url(${fontFiles.RufoBlackTTF}) format("ttf"), url(${fontFiles.RufoBlackWOFF}) format("woff");
}
// etc...
That seems like a lot of lines, but it's a one time thing to do for the project. It let us keep a CSS in JS direction, without a single CSS file out of place.
11/12/18: The example has been updated with the new createGlobalStyle syntax.
Is there a way currently to inline a given font in base64 inside the html file ?
@monsieurnebo's answer worked but with one little change
I had to change
format("ttf")
to
format("truetype")
@monsieurnebo tip worked like a charm here, thanks <3
I tried @monsieurnebo solution but it seems like it didn't detect injectGlobal
at all.
Repo: https://github.com/ajmalafif/gatsby-interUI/tree/master/src/shared/css Demo: https://gatsby-interui.netlify.com/
@ajmalafif Bcz for v4 injectGlobal
has been deprecated. Use createGlobalStyle instead.
@deadcoder0904 been pulling my hair, thanks for the heads up! Hopefully that helps others too. Thanks again!
The example has been updated with the new createGlobalStyle
syntax.
@monsieurnebo Hi I tried your method, and imported the globalStyles.js file into a component, styled one of the elements with a font that I imported, but when I gatsby build
and preview it on my github it doesn't work. The fonts aren't applied. Any suggestions?
@monsieurnebo 3 hours passed! Although I'm a beginner to React and Gatsby, I just can't stop pulling my hair for this!
Just for context I followed exactly what you've given, except using my own fonts, but the browser does not even detect a font. Chrome's dev tool under the Network tab does not display any fonts loaded. /static do have the fonts, and console logging one of the fonts (eg. fontfiles.fontFileWOFF) do display the minified/edited font file WHICH MEANS it does go through Gatsby's build process. Since the globalStyles.js was exported, I imported it into header.js, which I use for my logo and links.
Logically, this means that header.js component has the @font-face component implemented, hence applying the font in any element in the component SHOULD work. But nope. I thought I succeeded but when I publish to netlify and view the website on my phone its Times News Roman.
How do you make use of the globalStyles.js and how do you (correctly) import them?
Maybe that helps some future Google users: I implemented Inter UI with these fonts and CSS and added it to the Layout component while using gatsby-plugin-layout
@LekoArts Thank you so much! that fixed it. I think this should be the answer and anyone struggling with the earlier answer should follow that method. I think its clean and easy.
@alfianridwan createGlobalStyle
must be used as a (styled) component:
Returns a StyledComponent that does not accept children. Place it at the top of your React tree and the global styles will be injected when the component is "rendered". Source
Just use it in your root component (probably your pages). Based on my example, it would looks like that:
// RootComponent.jsx
import GlobalStyles from "shared/css/globalStyles.js";
export default RootComponent extends React.Component {
render() {
return (
<div>
<GlobalStyles />
{/* Your content... */}
</div>
);
}
}
The GlobalStyles
tag will inject the CSS into the whole project, making fonts accessible to further usage.
If you cannot manage to make it work, feel free to share a repository and I'll try to take a look at it.
@monsieurnebo does that mean you have to add that
@alfianridwan The feature provided by this plugin (layouts) has been removed in Gatsby v2, so yes, my example implies that you add this tag in every page.
However, you can avoid the code duplication by using a layout component, or the gatsby-plugin-layout
(that bring back the v1 feature). There is a explanation about this (and a little comparison between the two solutions) in the official migration guide from v1 to v2.
If you're really interested by the subject, you can read the related RFC (Request For Comments) that explains the whole reflexion.
@LekoArts solution worked for me.
Using @LekoArts approach... Would it be possible to configure Webpack to load the fonts using a <link rel=preload>
in the <head>
?
Currently getting this warning on lighthouse.
If you're using TypeScript make sure to add:
declare module "*.ttf";
After some discussions, we finally picked up the JS import solution in a dedicated file:
// shared/css/fonts.js import RufoBlackTTF from "fonts/RFRufo-Black.ttf"; import RufoBlackWOFF from "fonts/RFRufo-Black.woff"; import RufoBoldTTF from "fonts/RFRufo-Bold.ttf"; import RufoBoldWOFF from "fonts/RFRufo-Bold.woff"; import RufoSemiBoldTTF from "fonts/RFRufo-SemiBold.ttf"; import RufoSemiBoldWOFF from "fonts/RFRufo-SemiBold.woff"; import RobotoRegularTTF from "fonts/Roboto-Regular.ttf"; import RobotoBoldTTF from "fonts/Roboto-Bold.ttf"; import RobotoMediumTTF from "fonts/Roboto-Medium.ttf"; export { RufoBlackTTF, RufoBlackWOFF, RufoBoldTTF, RufoBoldWOFF, RufoSemiBoldTTF, RufoSemiBoldWOFF, RobotoRegularTTF, RobotoBoldTTF, RobotoMediumTTF };
Then used from the
@font-face
declaration:// shared/css/globalStyles.js import { createGlobalStyle } from "styled-components"; import fontFiles from "./fonts"; export default createGlobalStyle ` @font-face { font-family: "Rufo-Black"; font-style: normal; font-weight: normal; src: local("Rufo Black"), local("Rufo-Black"), url(${fontFiles.RufoBlackTTF}) format("ttf"), url(${fontFiles.RufoBlackWOFF}) format("woff"); } // etc...
That seems like a lot of lines, but it's a one time thing to do for the project. It let us keep a CSS in JS direction, without a single CSS file out of place.
11/12/18: The example has been updated with the new createGlobalStyle syntax.
@monsieurnebo This method will embed the font files into the js bundle, which is not ideal, especially for fonts that are low priority.
@monsieurnebo This method will embed the font files into the js bundle, which is not ideal, especially for fonts that are low priority.
What would you suggest then? 🤔
@monsieurnebo This method will embed the font files into the js bundle, which is not ideal, especially for fonts that are low priority.
What would you suggest then? 🤔
I'm using emotion
(with material-ui
v5). I end up simply create a CSS file and import it into my theme.js
. That kind of breaks the idea of 100% CSS in JS, but at least I don't have to increase the bundle size for no benifits.
I'm also looking for suggestions for a better way to handle this. In Create React App, if we import the font like you did, the "actual" path of the font file will be returned, instead of the base64 encoding of the font. I guess there could be a feature request for that?
Not sure if loading an external CSS file from server is worth it in order to avoid some extra bundle size weight. Especially if it requires adding one (two?) more dependency.
I think the difference is so small between these two methods... That it's more a question of preference than anything else :)
Thanks for your feedback 👍
I mean the point is, Gatsby will already embed some of the fonts into the HTML files, given that the font file is small. Now if we import the fonts directly from JS. It will also embed the font into the JS bundle. So in some cases, the fonts are embedded in BOTH the JS bundle and the HTML.
After some discussions, we finally picked up the JS import solution in a dedicated file:
// shared/css/fonts.js import RufoBlackTTF from "fonts/RFRufo-Black.ttf"; import RufoBlackWOFF from "fonts/RFRufo-Black.woff"; import RufoBoldTTF from "fonts/RFRufo-Bold.ttf"; import RufoBoldWOFF from "fonts/RFRufo-Bold.woff"; import RufoSemiBoldTTF from "fonts/RFRufo-SemiBold.ttf"; import RufoSemiBoldWOFF from "fonts/RFRufo-SemiBold.woff"; import RobotoRegularTTF from "fonts/Roboto-Regular.ttf"; import RobotoBoldTTF from "fonts/Roboto-Bold.ttf"; import RobotoMediumTTF from "fonts/Roboto-Medium.ttf"; export { RufoBlackTTF, RufoBlackWOFF, RufoBoldTTF, RufoBoldWOFF, RufoSemiBoldTTF, RufoSemiBoldWOFF, RobotoRegularTTF, RobotoBoldTTF, RobotoMediumTTF };
Then used from the
@font-face
declaration:// shared/css/globalStyles.js import { createGlobalStyle } from "styled-components"; import fontFiles from "./fonts"; export default createGlobalStyle ` @font-face { font-family: "Rufo-Black"; font-style: normal; font-weight: normal; src: local("Rufo Black"), local("Rufo-Black"), url(${fontFiles.RufoBlackTTF}) format("ttf"), url(${fontFiles.RufoBlackWOFF}) format("woff"); } // etc...
That seems like a lot of lines, but it's a one time thing to do for the project. It let us keep a CSS in JS direction, without a single CSS file out of place. 11/12/18: The example has been updated with the new createGlobalStyle syntax.
@monsieurnebo This method will embed the font files into the js bundle, which is not ideal, especially for fonts that are low priority.
I tried this solution and it doesn't embed the font files, it copies the files to the 'public' folder adding a hash to their names and sets the values of the imports to the paths of the generated font files, so this doesn't add to the bundle size.
I tried this solution and it doesn't embed the font files, it copies the files to the 'public' folder adding a hash to their names and sets the values of the imports to the paths of the generated font files, so this doesn't add to the bundle size.
Perhaps, that because I was using woff2
files and it doesn't go above the threshold.
I tried this solution and it doesn't embed the font files, it copies the files to the 'public' folder adding a hash to their names and sets the values of the imports to the paths of the generated font files, so this doesn't add to the bundle size.
Perhaps, that because I was using
woff2
files and it doesn't go above the threshold.
Makes sense, it depends on the file size whether an imported file is embedded or not. Perhaps there is a way to disable embedding font files by setting the threshold to 0 (just guessing, don't know how this works)?
Self-hosting fonts included in https://github.com/kyleamathews/typefaces is working great for me. However, I'm having trouble self-hosting other fonts.
Following the advice of @KyleAMathews in this issue, I created a
./src/fonts/
directory and put the font files there. I then imported the font files insrc/layouts/index.js
like this:I'm expecting to see the files copied to the
./public/
directory, but that isn't happening.Am I doing something wrong?