如何添加字体创建反应基于应用程序的项目?

我正在使用create-react-app,而不喜欢eject

不清楚通过@font-face导入并在本地加载的字体应该放在哪里。

也就是说,我在装载

@font-face {
font-family: 'Myriad Pro Regular';
font-style: normal;
font-weight: normal;
src: local('Myriad Pro Regular'), url('MYRIADPRO-REGULAR.woff') format('woff');
}

有什么建议吗?

——编辑

包括丹在回答中提到的要点

➜  Client git:(feature/trivia-game-ui-2) ✗ ls -l public/static/fonts
total 1168
-rwxr-xr-x@ 1 maximveksler  staff  62676 Mar 17  2014 MYRIADPRO-BOLD.woff
-rwxr-xr-x@ 1 maximveksler  staff  61500 Mar 17  2014 MYRIADPRO-BOLDCOND.woff
-rwxr-xr-x@ 1 maximveksler  staff  66024 Mar 17  2014 MYRIADPRO-BOLDCONDIT.woff
-rwxr-xr-x@ 1 maximveksler  staff  66108 Mar 17  2014 MYRIADPRO-BOLDIT.woff
-rwxr-xr-x@ 1 maximveksler  staff  60044 Mar 17  2014 MYRIADPRO-COND.woff
-rwxr-xr-x@ 1 maximveksler  staff  64656 Mar 17  2014 MYRIADPRO-CONDIT.woff
-rwxr-xr-x@ 1 maximveksler  staff  61848 Mar 17  2014 MYRIADPRO-REGULAR.woff
-rwxr-xr-x@ 1 maximveksler  staff  62448 Mar 17  2014 MYRIADPRO-SEMIBOLD.woff
-rwxr-xr-x@ 1 maximveksler  staff  66232 Mar 17  2014 MYRIADPRO-SEMIBOLDIT.woff
➜  Client git:(feature/trivia-game-ui-2) ✗ cat src/containers/GameModule.css
.GameModule {
padding: 15px;
}


@font-face {
font-family: 'Myriad Pro Regular';
font-style: normal;
font-weight: normal;
src: local('Myriad Pro Regular'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-REGULAR.woff') format('woff');
}


@font-face {
font-family: 'Myriad Pro Condensed';
font-style: normal;
font-weight: normal;
src: local('Myriad Pro Condensed'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-COND.woff') format('woff');
}


@font-face {
font-family: 'Myriad Pro Semibold Italic';
font-style: normal;
font-weight: normal;
src: local('Myriad Pro Semibold Italic'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-SEMIBOLDIT.woff') format('woff');
}


@font-face {
font-family: 'Myriad Pro Semibold';
font-style: normal;
font-weight: normal;
src: local('Myriad Pro Semibold'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-SEMIBOLD.woff') format('woff');
}


@font-face {
font-family: 'Myriad Pro Condensed Italic';
font-style: normal;
font-weight: normal;
src: local('Myriad Pro Condensed Italic'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-CONDIT.woff') format('woff');
}


@font-face {
font-family: 'Myriad Pro Bold Italic';
font-style: normal;
font-weight: normal;
src: local('Myriad Pro Bold Italic'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-BOLDIT.woff') format('woff');
}


@font-face {
font-family: 'Myriad Pro Bold Condensed Italic';
font-style: normal;
font-weight: normal;
src: local('Myriad Pro Bold Condensed Italic'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-BOLDCONDIT.woff') format('woff');
}


@font-face {
font-family: 'Myriad Pro Bold Condensed';
font-style: normal;
font-weight: normal;
src: local('Myriad Pro Bold Condensed'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-BOLDCOND.woff') format('woff');
}


@font-face {
font-family: 'Myriad Pro Bold';
font-style: normal;
font-weight: normal;
src: local('Myriad Pro Bold'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-BOLD.woff') format('woff');
}
423876 次浏览

有两种选择:

使用进口

这是建议的选项。它确保您的字体通过构建管道,在编译期间获得哈希值,以便浏览器缓存正确工作,并且如果文件丢失,您将得到编译错误。

作为在“添加图像、字体和文件”中描述,你需要从JS中导入一个CSS文件。例如,默认情况下,src/index.js导入src/index.css:

import './index.css';

这样的CSS文件通过构建管道,可以引用字体和图像。例如,如果你在src/fonts/MyFont.woff中放入一个字体,你的index.css可能包括:

@font-face {
font-family: 'MyFont';
src: local('MyFont'), url(./fonts/MyFont.woff) format('woff');
/* other formats include: 'woff2', 'truetype, 'opentype',
'embedded-opentype', and 'svg' */
}

注意我们是如何使用以./开头的相对路径的。这是一种特殊的符号,可以帮助构建管道(由Webpack提供支持)发现该文件。

通常这就足够了。

使用public文件夹

如果出于某种原因,你更喜欢使用构建管道,而不是“经典的方式”,你可以使用public文件夹并把你的字体放在那里。

这种方法的缺点是,在编译用于生产时,文件不会得到哈希值,因此每次更改它们时都必须更新它们的名称,否则浏览器将缓存旧版本。

如果你想这样做,把字体放在public文件夹的某个地方,例如,在public/fonts/MyFont.woff。如果你采用这种方法,你也应该把CSS文件放在public文件夹中,并从JS中导入,因为混合这些方法会非常混乱。所以,如果你仍然想这样做,你会有一个类似public/index.css的文件。你必须手动将<link>public/index.html添加到这个样式表:

<link rel="stylesheet" href="%PUBLIC_URL%/index.css">

在里面,你会使用常规的CSS符号:

@font-face {
font-family: 'MyFont';
src: local('MyFont'), url(fonts/MyFont.woff) format('woff');
}

注意我是如何使用fonts/MyFont.woff作为路径的。这是因为index.csspublic文件夹中,所以它将从公共路径(通常是服务器根路径,但如果你部署到GitHub Pages并将你的homepage字段设置为http://myuser.github.io/myproject,它将从/myproject提供服务)。然而,fonts也在public文件夹中,因此它们将相对地从fonts提供(http://mywebsite.example/fontsindex.css0)。因此我们使用相对路径。

注意,由于我们在本例中避免了构建管道,因此它不会验证文件是否实际存在。这就是我不推荐这种方法的原因。另一个问题是我们的index.css文件没有被缩小,也没有得到哈希值。因此,对于最终用户来说,速度会变慢,而且浏览器可能会缓存旧版本的文件。

使用哪种方式?

使用第一个方法(“使用导入”)。我只描述了第二个,因为这是你试图做的(从你的评论来看),但它有很多问题,应该是你在解决某些问题时的最后手段。

你可以使用WebFont模块,它极大地简化了这个过程。

render(){
webfont.load({
custom: {
families: ['MyFont'],
urls: ['/fonts/MyFont.woff']
}
});
return (
<div style={your style} >
your text!
</div>
);
}

我犯了这样的错误。

@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i&amp;subset=cyrillic,cyrillic-ext,latin-ext";
@import "https://use.fontawesome.com/releases/v5.3.1/css/all.css";

它以这种方式正常工作

@import url(https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i&amp;subset=cyrillic,cyrillic-ext,latin-ext);
@import url(https://use.fontawesome.com/releases/v5.3.1/css/all.css);

以下是一些做到这一点的方法:

1. 导入字体

例如,要使用Roboto,请使用

yarn add typeface-roboto

npm install typeface-roboto --save

在index.js:

import "typeface-roboto";

有很多开源字体和大部分谷歌字体的npm包。你可以看到所有的字体在这里。所有的包都来自那个项目

2. 对于由第三方托管的字体

例如谷歌字体,你可以去fonts.google.com,在那里你可以找到可以放在你的public/index.html中的链接

截图of fonts.google.com

就像这样

<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">

<style>
@import url('https://fonts.googleapis.com/css?family=Montserrat');
</style>

3.下载字体并将其添加到源代码中。

下载字体。例如,对于谷歌字体,你可以去fonts.google.com。点击下载按钮下载字体。

将字体移动到你的src目录中的fonts目录

src
|
`----fonts
|      |
|      `-Lato/Lato-Black.ttf
|       -Lato/Lato-BlackItalic.ttf
|       -Lato/Lato-Bold.ttf
|       -Lato/Lato-BoldItalic.ttf
|       -Lato/Lato-Italic.ttf
|       -Lato/Lato-Light.ttf
|       -Lato/Lato-LightItalic.ttf
|       -Lato/Lato-Regular.ttf
|       -Lato/Lato-Thin.ttf
|       -Lato/Lato-ThinItalic.ttf
|
`----App.css

现在,在App.css中添加这个

@font-face {
font-family: 'Lato';
src: local('Lato'), url(./fonts/Lato-Regular.otf) format('opentype');
}


@font-face {
font-family: 'Lato';
font-weight: 900;
src: local('Lato'), url(./fonts/Lato-Bold.otf) format('opentype');
}


@font-face {
font-family: 'Lato';
font-weight: 900;
src: local('Lato'), url(./fonts/Lato-Black.otf) format('opentype');
}

对于ttf格式,你必须提到format('truetype')。对于woffformat('woff')

现在你可以在课堂上使用这种字体了。

.modal-title {
font-family: Lato, Arial, serif;
font-weight: black;
}

4. 使用web-font-loader包

使用

yarn add webfontloader

npm install webfontloader --save

src/index.js中,你可以导入它并指定所需的字体

import WebFont from 'webfontloader';


WebFont.load({
google: {
families: ['Titillium Web:300,400,700', 'sans-serif']
}
});
  1. 转到谷歌Fonts https://fonts.google.com/
  2. 选择如下图所示的字体:

enter image description here

  1. 复制并粘贴该url在新选项卡,你会得到css代码添加该字体。在这种情况下,如果你去

https://fonts.googleapis.com/css?family=Spicy+Rice

它会像这样打开:

enter image description here

4、复制并粘贴到你的style.css中,然后像这样简单地开始使用那种字体:

      <Typography
variant="h1"
gutterBottom
style=\{\{ fontFamily: "Spicy Rice", color: "pink" }}
>
React Rock
</Typography>

结果:

enter image description here

我花了整个上午的时间来解决这个堆栈问题。我在上面的答案中使用了Dan的第一个解决方案作为出发点。

问题

我有一个开发(在我的本地机器上)、登台和生产环境。我的登台和生产环境位于同一台服务器上。

应用程序通过acmeserver/~staging/note-taking-app部署到登台,生产版本位于acmeserver/note-taking-app(怪IT)。

所有的媒体文件,比如字体,都在dev上加载得很好(例如,react-scripts start)。

然而,当我创建并上传登台和生产版本时,虽然.css.js文件加载正常,但字体却不能。编译后的.css文件看起来有一个正确的路径,但浏览器http请求得到了一些非常错误的路径(如下所示)。

编译后的main.fc70b10f.chunk.css文件:

@font-face {
font-family: SairaStencilOne-Regular;
src: url(note-taking-app/static/media/SairaStencilOne-Regular.ca2c4b9f.ttf) ("truetype");
}

浏览器http请求如下所示。注意,当字体文件只存在于/static/media/中时,它是如何在/static/css/中添加的,以及如何复制目标文件夹。我排除了服务器配置是罪魁祸首的可能性。

Referer也有部分错误。

GET /~staging/note-taking-app/static/css/note-taking-app/static/media/SairaStencilOne-Regular.ca2c4b9f.ttf HTTP/1.1
Host: acmeserver
Origin: http://acmeserver
Referer: http://acmeserver/~staging/note-taking-app/static/css/main.fc70b10f.chunk.css

package.json文件将homepage属性设置为./note-taking-app。这就是问题的根源。

{
"name": "note-taking-app",
"version": "0.1.0",
"private": true,
"homepage": "./note-taking-app",
"scripts": {
"start": "env-cmd -e development react-scripts start",
"build": "react-scripts build",
"build:staging": "env-cmd -e staging npm run build",
"build:production": "env-cmd -e production npm run build",
"test": "react-scripts test",
"eject": "react-scripts eject"
}
//...
}

解决方案

这很冗长,但解决方案是:

  1. 根据环境改变PUBLIC_URL env变量
  2. package.json文件中删除homepage属性

下面是我的.env-cmdrc文件。我使用.env-cmdrc而不是常规的.env,因为它将所有内容都放在一个文件中。

{
"development": {
"PUBLIC_URL": "",
"REACT_APP_API": "http://acmeserver/~staging/note-taking-app/api"
},
"staging": {
"PUBLIC_URL": "/~staging/note-taking-app",
"REACT_APP_API": "http://acmeserver/~staging/note-taking-app/api"
},
"production": {
"PUBLIC_URL": "/note-taking-app",
"REACT_APP_API": "http://acmeserver/note-taking-app/api"
}
}

通过react-router-dom进行路由也很好-只需使用PUBLIC_URL env变量作为basename属性。

import React from "react";
import { BrowserRouter } from "react-router-dom";


const createRouter = RootComponent => (
<BrowserRouter basename={process.env.PUBLIC_URL}>
<RootComponent />
</BrowserRouter>
);


export { createRouter };

服务器配置被设置为将所有请求路由到./index.html文件。

最后,下面是实现了所讨论的更改后编译的main.fc70b10f.chunk.css文件的样子。

@font-face {
font-family: SairaStencilOne-Regular;
src: url(/~staging/note-taking-app/static/media/SairaStencilOne-Regular.ca2c4b9f.ttf)
format("truetype");
}

阅读材料

链接到react js的本地字体可能会失败。所以,我更喜欢使用在线css文件从谷歌链接字体。参考以下代码,

<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">

<style>
@import url('https://fonts.googleapis.com/css?family=Roboto');
</style>

你可以在不需要CSS的情况下使用Web API字体构造函数(也是Typescript):

export async function loadFont(fontFamily: string, url: string): Promise<void> {
const font = new FontFace(fontFamily, `local(${fontFamily}), url(${url})`);
// wait for font to be loaded
await font.load();
// add font to document
document.fonts.add(font);
// enable font with CSS class
document.body.classList.add("fonts-loaded");
}
import ComicSans from "./assets/fonts/ComicSans.ttf";


loadFont("Comic Sans ", ComicSans).catch((e) => {
console.log(e);
});

声明一个文件font.ts与你的模块(仅TS):

declare module "*.ttf";
declare module "*.woff";
declare module "*.woff2";

如果TS无法找到FontFace类型作为其正式的在制品,则将这个声明添加到您的项目中。它可以在你的浏览器中运行,除了IE。

当为正常/斜体font-style使用不同的字体文件时,根据入口点的不同,指定@font-face的方式可能需要不同。点击这里查看我的答案:

  1. 如果你选择将css文件直接链接到你的public/index.html,那么你通常可以使用带有一个font-family名称和不同的font-stylefont-face:
@font-face {
font-family: "FontName"; <---
font-style: normal; <---
font-weight: normal;
src: url("path-to-assets/fonts/FontName.ttf") format("truetype");
}
@font-face {
font-family: "FontName"; <---
font-style: italic; <---
font-weight: normal;
src: url("path-to-assets/fonts/FontName-Italic.ttf") format("truetype");
}


/* Usage */
.text {
font-family: FontName;
font-style: normal;
}
.text-italic {
font-family: FontName;
font-style: italic;
}
  1. 如果你选择通过Js链接css文件进行捆绑,那么你需要为所有的italic字体有一个不同的font-family名称,并使用font-style normal。
@font-face {
font-family: "FontName"; <---
font-style: normal; <---
font-weight: normal; /* normal | 300 | 400 | 600 | bold | etc */
src: url("path-to-assets/fonts/FontName.ttf") format("truetype");
}
@font-face {
font-family: "FontNameItalic";
font-style: normal; <----
font-weight: normal; /* normal | 300 | 400 | 600 | bold | etc */
src: url("path-to-assets/fonts/FontName-Italic.ttf") format("truetype");
}


/* Usage */
.text {
font-family: FontName;
}
.text-italic {
font-family: FontNameItalic;
}

我添加了

@font-face {
font-family: 'Sanchez-Regular';
src: local('Sanchez-Regular'),url(../assets/fonts/Sanchez/Sanchez-Regular.ttf) format('truetype');
}

,效果非常好 就像我们在index.css

中使用其他字体一样,稍后再使用它

这是为使用NX(nwrl) monorepo的人准备的,我在那里使用它时测试了这个,可能适用于其他CRA应用程序。 首先在assets/fonts文件夹中添加字体,如果没有,创建一个fonts文件夹 然后在你的主app.js/tsx中 使用现有的jsx代码

添加此代码
<style type="text/css">{`
@font-face {
font-family: 'MaterialIcons';
src: url(${require('react-native-vector-icons/Fonts/MaterialIcons.ttf')}) format('truetype');
}
@font-face {
font-family: 'MaterialCommunityIcons';
src: url(${require('react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf')}) format('truetype');
}
@font-face {
font-family: 'Mulish-Bold';
src: url(${require('../assets/fonts/Mulish-Bold.ttf')}) format('truetype');
}
@font-face {
font-family: 'Your Font Name';
src: url(${require('../assets/fonts/font-file-name.otf')}) format('truetype');
}
`}</style>

它应该看起来像这样,用Fragment标签包装

 <>
<style type="text/css">{`
@font-face {
font-family: 'MaterialIcons';
src: url(${require('react-native-vector-icons/Fonts/MaterialIcons.ttf')}) format('truetype');
}
@font-face {
font-family: 'MaterialCommunityIcons';
src: url(${require('react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf')}) format('truetype');
}
@font-face {
font-family: 'Mulish-Bold';
src: url(${require('../assets/fonts/Mulish-Bold.ttf')}) format('truetype');
}
@font-face {
font-family: 'CircularStd-Book';
src: url(${require('../assets/fonts/CircularStd-Book.otf')}) format('truetype');
}
`}</style>
//Your JSX, or your main app level code
</>

还有另一个步骤,在你的自定义webpack配置文件中,添加这些加载器,如果你没有,那么在你的父级,创建一个webpack.js文件-

你的webpack js应该是这样的

const getWebpackConfig = require('@nrwl/react/plugins/webpack');


function getCustomWebpackConfig(webpackConfig) {
const config = getWebpackConfig(webpackConfig);
const isProduction = webpackConfig.mode === 'production';


if (!isProduction) {
config.resolve.alias = {
'react-native': 'react-native-web',
'react-native-linear-gradient': 'react-native-web-linear-gradient',
'react-native-localization': 'react-localization'
};


config.module.rules.push(
{
test: /\.ttf$/,
loader: require.resolve('file-loader'),
options: { esModule: false, name: 'static/media/[path][name].[ext]' },
},
{
test: /\.otf$/,
loader: require.resolve('file-loader'),
options: { esModule: false, name: 'static/media/[path][name].[ext]' },
},
{
test: /\.(js|jsx)$/,
exclude: function (content) {
return (
/node_modules/.test(content) &&
!/\/react-native-paper\//.test(content) &&
!/\/react-native-vector-icons\//.test(content) &&
          

);
},
use: {
loader: require.resolve('@nrwl/web/src/utils/web-babel-loader.js'),
options: {
presets: [
[
'@nrwl/react/babel',
{
runtime: 'automatic',
useBuiltIns: 'usage',
},
],
],
plugins: [
["module-resolver", {
"alias": {
"^react-native$": "react-native-web",
"react-native-linear-gradient": "react-native-web-linear-gradient",
"react-native-localization": "react-localization"
}
}]
],
},
},
},
      

);
}


return config;
}


module.exports = getCustomWebpackConfig;

您的babel加载器可能不同,但ttf和otf规则是重要的,需要添加。我使用这个与react原生的web功能。如果您的项目不需要别名,则可以删除别名。

感谢这个博客,它让我更好地理解了这个概念——https://blog.nrwl.io/step-by-step-guide-on-creating-a-monorepo-for-react-native-apps-using-nx-704753b6c70e

我的感觉是,如果你在你的网站上本地托管字体,你应该能够使用CSS字体加载API来为你在运行时加载字体,而不使用CSS文件。这是我写的一个React组件。它基于上面的user-rebo回答,但尝试在使用后卸载字体。它似乎可以在火狐和Chrome浏览器中运行。代码是:

import React, { useEffect, PropsWithChildren, useRef } from "react";


type FontFaceFormat =
| "woff"
| "woff2"
| "truetype"
| "opentype"
| "embedded-opentype"
| "svg";


type FontWrapperProps = {
fontName: string;
fontURL: string;
fontFormat?: FontFaceFormat;
};


/*
* The FontWrapper class. Takes a fontName (like "Andika"), a fontURL (which
* should go to the website's public folder), and an optional font type. Usage
* should be as simple as:
*
* <FontWrapper fontName="Andika" fontURL="/fonts/Andika-Regular.ttf.woff2">
*   <p>This is some text</p>
* </FontWrapper>
*
* Note: document.fonts is of type FontFaceSet, which should include the add() and
* delete() methods. However, the TypeScript libraries for Visual Studio Code
* miss these. That's why I have two instances of "document.fonts as any" -
* to make those red lines go away.
*/


export default function FontWrapper({
fontName,
fontURL,
fontFormat = "woff2",
children,
}: PropsWithChildren<FontWrapperProps>) {
const fontRef = useRef(null);


useEffect(() => {
const loadFont = async () => {
const font = new FontFace(
fontName,
`url(${fontURL}) format("${fontFormat}")`,
{}
);
const fontResult = await font.load();
fontRef.current = fontResult;
await (document.fonts as any).add(font);
};


const unloadFont = async () => {
await (document.fonts as any).delete(fontRef.current);
};


loadFont();


return () => {
unloadFont();
};
}, []);


return <div style=\{\{ fontFamily: fontName }}>{children}</div>;
}




用法是:

<FontWrapper fontName="Andika" fontURL="/fonts/Andika-Regular.ttf.woff2">
<p>This is some text</p>
</FontWrapper>