如何将字体添加到基于 create-react-app 的项目?
How to add fonts to create-react-app based projects?
我正在使用 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');
}
有两个选项:
使用导入
这是建议的选项。它确保您的字体通过构建管道,在编译期间获取哈希值,以便浏览器缓存正常工作,并且如果文件丢失,您会收到编译错误。
作为described in “Adding Images, Fonts, and Files”,您需要从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
文件夹
如果出于某种原因你更喜欢 而不是 使用构建管道,而是使用“经典方式”,你可以 use the public
folder 并将你的字体放在那里.
这种方法的缺点是,当您为生产环境编译时,文件不会得到散列值,因此您必须在每次更改它们时更新它们的名称,否则浏览器会缓存旧版本。
如果您想这样做,请将字体放入 public
文件夹的某个位置,例如 public/fonts/MyFont.woff
。如果您采用这种方法,您应该将 CSS 文件也放入 public
文件夹中,并且 而不是 从 JS 导入它们,因为混合这些方法会非常混乱.所以,如果你仍然想这样做,你会有一个像 public/index.css
这样的文件。您必须从 public/index.html
:
手动将 <link>
添加到此样式表
<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.css
位于 public
文件夹中,因此将从 public 路径提供服务(通常是服务器根目录,但如果您部署到 GitHub 页面并设置您的 homepage
字段到 http://myuser.github.io/myproject
,它将从 /myproject
提供)。但是 fonts
也在 public
文件夹中,因此它们将从 fonts
相对(http://mywebsite.com/fonts
或 http://myuser.github.io/myproject/fonts
)提供。因此我们使用相对路径。
请注意,由于我们在此示例中避免了构建管道,因此它不会验证文件是否确实存在。这就是我不推荐这种方法的原因。另一个问题是我们的 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&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&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";
许多开源字体和大多数 Google 字体都有 npm 包。可以看到所有字体here. All the packages are from that project.
2。对于第三方托管的字体
例如 Google 字体,您可以转到 fonts.google.com,在那里您可以找到可以放入 public/index.html
中的链接
会像
<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
或
<style>
@import url('https://fonts.googleapis.com/css?family=Montserrat');
</style>
3。下载字体并将其添加到您的源代码中。
下载字体。例如,对于 google 字体,您可以转到 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')
。对于 woff
、format('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']
}
});
- 转到 Google 字体 https://fonts.google.com/
- Select 您的字体如下图所示:
- 复制 url 并将其粘贴到新选项卡中,您将获得 css 代码以添加该字体。在这种情况下,如果你去
会这样打开:
4,将该代码复制并粘贴到您的 style.css 中,然后像这样开始使用该字体:
<Typography
variant="h1"
gutterBottom
style={{ fontFamily: "Spicy Rice", color: "pink" }}
>
React Rock
</Typography>
结果:
在解决了这个堆栈问题后,我花了整个上午解决了一个类似的问题。我在上面的答案中使用了 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"
}
//...
}
解决方案
那是啰嗦——但解决方案是:
- 根据环境更改
PUBLIC_URL
env 变量
- 从
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
环境变量作为 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");
}
阅读material
https://create-react-app.dev/docs/deployment#serving-apps-with-client-side-routing
https://create-react-app.dev/docs/advanced-configuration
- 这解释了
PUBLIC_URL
环境变量
Create React App assumes your application is hosted at the serving web server's root or a subpath as specified in package.json (homepage). Normally, Create React App ignores the hostname. You may use this variable to force assets to be referenced verbatim to the url you provide (hostname included). This may be particularly useful when using a CDN to host your application.
本地字体 linking 到您的 React js 可能会失败。所以,我更喜欢使用在线 css 文件从 google 到 link 字体。参考以下代码,
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
或
<style>
@import url('https://fonts.googleapis.com/css?family=Roboto');
</style>
您可以使用 Web API FontFace 构造函数(也是 Typescript)而不需要 CSS:
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);
});
与您的模块(仅限 TS):
declare module "*.ttf";
declare module "*.woff";
declare module "*.woff2";
如果 TS 找不到 FontFace 类型,因为它仍然是正式的 WIP,请将 this declaration 添加到您的项目中。它可以在您的浏览器中使用,IE 除外。
当 normal/italic font-style
使用不同的字体文件时,您指定 @font-face
的方式可能需要根据入口点而有所不同。 See my answer here:
- 如果您选择 link
css
文件直接到您的 public/index.html
那么您可以正常使用 font-face
一个 font-family
名称和不同的 font-style
:
@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;
}
- 如果您选择 link 通过 Js 打包
css
文件,那么您需要为所有 italic
字体设置不同的 font-family
名称并使用font-style
正常。
@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文件夹中添加字体,创建一个字体文件夹,如果不存在。
然后在您的主应用程序中。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 Native 一起用于 Web 功能。如果您的项目不需要,您可以删除别名。
感谢这个博客,让我更好地理解了这个概念 - https://blog.nrwl.io/step-by-step-guide-on-creating-a-monorepo-for-react-native-apps-using-nx-704753b6c70e
我正在使用 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');
}
有两个选项:
使用导入
这是建议的选项。它确保您的字体通过构建管道,在编译期间获取哈希值,以便浏览器缓存正常工作,并且如果文件丢失,您会收到编译错误。
作为described in “Adding Images, Fonts, and Files”,您需要从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
文件夹
如果出于某种原因你更喜欢 而不是 使用构建管道,而是使用“经典方式”,你可以 use the public
folder 并将你的字体放在那里.
这种方法的缺点是,当您为生产环境编译时,文件不会得到散列值,因此您必须在每次更改它们时更新它们的名称,否则浏览器会缓存旧版本。
如果您想这样做,请将字体放入 public
文件夹的某个位置,例如 public/fonts/MyFont.woff
。如果您采用这种方法,您应该将 CSS 文件也放入 public
文件夹中,并且 而不是 从 JS 导入它们,因为混合这些方法会非常混乱.所以,如果你仍然想这样做,你会有一个像 public/index.css
这样的文件。您必须从 public/index.html
:
<link>
添加到此样式表
<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.css
位于 public
文件夹中,因此将从 public 路径提供服务(通常是服务器根目录,但如果您部署到 GitHub 页面并设置您的 homepage
字段到 http://myuser.github.io/myproject
,它将从 /myproject
提供)。但是 fonts
也在 public
文件夹中,因此它们将从 fonts
相对(http://mywebsite.com/fonts
或 http://myuser.github.io/myproject/fonts
)提供。因此我们使用相对路径。
请注意,由于我们在此示例中避免了构建管道,因此它不会验证文件是否确实存在。这就是我不推荐这种方法的原因。另一个问题是我们的 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&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&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";
许多开源字体和大多数 Google 字体都有 npm 包。可以看到所有字体here. All the packages are from that project.
2。对于第三方托管的字体
例如 Google 字体,您可以转到 fonts.google.com,在那里您可以找到可以放入 public/index.html
会像
<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
或
<style>
@import url('https://fonts.googleapis.com/css?family=Montserrat');
</style>
3。下载字体并将其添加到您的源代码中。
下载字体。例如,对于 google 字体,您可以转到 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')
。对于 woff
、format('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']
}
});
- 转到 Google 字体 https://fonts.google.com/
- Select 您的字体如下图所示:
- 复制 url 并将其粘贴到新选项卡中,您将获得 css 代码以添加该字体。在这种情况下,如果你去
会这样打开:
4,将该代码复制并粘贴到您的 style.css 中,然后像这样开始使用该字体:
<Typography
variant="h1"
gutterBottom
style={{ fontFamily: "Spicy Rice", color: "pink" }}
>
React Rock
</Typography>
结果:
在解决了这个堆栈问题后,我花了整个上午解决了一个类似的问题。我在上面的答案中使用了 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"
}
//...
}
解决方案
那是啰嗦——但解决方案是:
- 根据环境更改
PUBLIC_URL
env 变量 - 从
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
环境变量作为 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");
}
阅读material
https://create-react-app.dev/docs/deployment#serving-apps-with-client-side-routing
https://create-react-app.dev/docs/advanced-configuration
- 这解释了
PUBLIC_URL
环境变量Create React App assumes your application is hosted at the serving web server's root or a subpath as specified in package.json (homepage). Normally, Create React App ignores the hostname. You may use this variable to force assets to be referenced verbatim to the url you provide (hostname included). This may be particularly useful when using a CDN to host your application.
- 这解释了
本地字体 linking 到您的 React js 可能会失败。所以,我更喜欢使用在线 css 文件从 google 到 link 字体。参考以下代码,
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
或
<style>
@import url('https://fonts.googleapis.com/css?family=Roboto');
</style>
您可以使用 Web API FontFace 构造函数(也是 Typescript)而不需要 CSS:
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);
});
declare module "*.ttf";
declare module "*.woff";
declare module "*.woff2";
如果 TS 找不到 FontFace 类型,因为它仍然是正式的 WIP,请将 this declaration 添加到您的项目中。它可以在您的浏览器中使用,IE 除外。
当 normal/italic font-style
使用不同的字体文件时,您指定 @font-face
的方式可能需要根据入口点而有所不同。 See my answer here:
- 如果您选择 link
css
文件直接到您的public/index.html
那么您可以正常使用font-face
一个font-family
名称和不同的font-style
:
@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;
}
- 如果您选择 link 通过 Js 打包
css
文件,那么您需要为所有italic
字体设置不同的font-family
名称并使用font-style
正常。
@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文件夹中添加字体,创建一个字体文件夹,如果不存在。
然后在您的主应用程序中。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 Native 一起用于 Web 功能。如果您的项目不需要,您可以删除别名。
感谢这个博客,让我更好地理解了这个概念 - https://blog.nrwl.io/step-by-step-guide-on-creating-a-monorepo-for-react-native-apps-using-nx-704753b6c70e