我正在使用 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');
}
%PUBLIC_URL%
在 CSS 文件中不起作用(并且是不必要的)。此外,如指南中所述,您应该在几乎所有情况下都使用 JS 导入,而不是公用文件夹。
有两种选择:
使用导入
这是建议的选项。它确保您的字体通过构建管道,在编译期间获取哈希值,以便浏览器缓存正常工作,并且如果文件丢失,您会收到编译错误。
作为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 提供支持)发现这个文件。
通常这应该足够了。
使用公用文件夹
如果出于某种原因您希望不使用构建管道,而是使用“经典方式”,您可以use the public
folder将您的字体放在那里。
这种方法的缺点是当您为生产编译时文件不会得到哈希值,因此您每次更改它们时都必须更新它们的名称,否则浏览器将缓存旧版本。
如果您想这样做,请将字体放在 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.css
位于 public
文件夹中,因此它将从公共路径(通常是服务器根目录,但如果您部署到 GitHub Pages 并将 homepage
字段设置为 http://myuser.github.io/myproject
,它将从 /myproject
提供)。但是 fonts
也在 public
文件夹中,因此它们将从 fonts
相对提供(http://mywebsite.example/fonts
或 http://myuser.github.io/myproject/fonts
)。因此我们使用相对路径。
请注意,由于我们在此示例中避免了构建管道,因此它不会验证文件是否确实存在。这就是我不推荐这种方法的原因。另一个问题是我们的 index.css
文件没有被缩小并且没有得到散列。因此,最终用户的速度会变慢,并且您会冒着浏览器缓存文件旧版本的风险。
使用哪种方式?
使用第一种方法(“使用导入”)。我只描述了第二个,因为那是你试图做的(从你的评论来看),但它有很多问题,只有在你解决某些问题时才应该是最后的手段。
以下是一些执行此操作的方法:
1.导入字体
例如,对于使用 Roboto,安装包使用
yarn add typeface-roboto
或者
npm install typeface-roboto --save
在 index.js 中:
import "typeface-roboto";
许多开源字体和大多数 Google 字体都有 npm 包。您可以看到所有字体 here。所有的包都来自那个project。
2. 对于第三方托管的字体
例如 Google 字体,您可以转到 fonts.google.com 找到可以放入 public/index.html
的链接
https://i.stack.imgur.com/byTI5.png
它会像
<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']
}
});
fonts
文件夹放在 src
下,而是放在 public
下?我试过了,但似乎不允许...
For ttf format, you have to mention format('truetype'). For woff, format('woff')
为我做的!谢谢你!
woff2
cli 工具并使用其在 Google 字体 TTF 下载文件上的 woff2_compress
二进制文件来为网络压缩它们。在您的 @font-face
规则中使用 font-display
rule 来加快速度。最后,您只需要为 Web 发送 WOFF2 文件。
转到 Google 字体 https://fonts.google.com/ 选择您的字体,如下图所示:
https://i.stack.imgur.com/ekX7F.png
复制然后将该 url 粘贴到新选项卡中,您将获得用于添加该字体的 css 代码。在这种情况下,如果你去
https://fonts.googleapis.com/css?family=Spicy+Rice
它将像这样打开:
https://i.stack.imgur.com/GxjHx.png
4,将代码复制并粘贴到您的 style.css 中,然后开始使用该字体,如下所示:
<Typography
variant="h1"
gutterBottom
style={{ fontFamily: "Spicy Rice", color: "pink" }}
>
React Rock
</Typography>
结果:
https://i.stack.imgur.com/udJ77.png
链接到您的 react js 的本地字体可能会失败。所以,我更喜欢使用 google 的在线 css 文件来链接字体。参考以下代码,
<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 a file font.ts
与您的模块(仅限 TS):
declare module "*.ttf";
declare module "*.woff";
declare module "*.woff2";
如果 TS 找不到 FontFace 类型作为其仍然正式的 WIP,请将 this declaration 添加到您的项目中。它将在您的浏览器中运行,IE 除外。
当对普通/斜体 font-style
使用不同的字体文件时,您指定 @font-face
的方式可能需要根据入口点而有所不同。 See my answer here:
如果您选择将 css 文件直接链接到您的 public/index.html ,那么您可以正常使用具有一个字体系列名称和不同字体样式的字体:
@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;
}
如果您选择通过 Js 链接 css 文件进行捆绑,那么您需要为所有斜体字体使用不同的字体系列名称并使用 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;
}
您可以使用 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);
在遇到这个堆栈问题后,我整个上午都在解决类似的问题。我在上面的答案中使用了丹的第一个解决方案作为起点。
问题
我有一个开发(这是在我的本地机器上)、登台和生产环境。我的登台和生产环境位于同一台服务器上。
该应用程序通过 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 环境变量 从 package.json 文件中删除主页属性
下面是我的 .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");
}
阅读材料
https://create-react-app.dev/docs/adding-custom-environment-variables#adding-development-environment-variables-in-env
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 假设您的应用程序托管在服务 Web 服务器的根目录或 package.json(主页)中指定的子路径。通常,Create React App 会忽略主机名。您可以使用此变量强制将资产逐字引用到您提供的 url(包括主机名)。这在使用 CDN 托管您的应用程序时可能特别有用。
这解释了 PUBLIC_URL 环境变量 Create React App 假设您的应用程序托管在服务 Web 服务器的根目录或 package.json(主页)中指定的子路径。通常,Create React App 会忽略主机名。您可以使用此变量强制将资产逐字引用到您提供的 url(包括主机名)。这在使用 CDN 托管您的应用程序时可能特别有用。
我添加了
@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 文件夹中添加字体,如果不存在,则创建一个字体文件夹。
然后在您的主 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 native 一起用于 Web 功能。如果您的项目不需要别名,您可以删除别名。
感谢这个博客,它让我更好地理解了这个概念 - https://blog.nrwl.io/step-by-step-guide-on-creating-a-monorepo-for-react-native-apps-using-nx-704753b6c70e
不定期副业成功案例分享
ttf
字体,您应该将truetype
而不是ttf
作为参数提供给format
*。otf
,请关注 @milkersarac,您需要输入opentype
。bold
、bold+italic
、..)?这个应该有帮助:stackoverflow.com/a/2436830/3592419