如何为基于create-react-app的项目添加字体?

时间:2017-01-16 12:04:47

标签: css reactjs fonts webpack create-react-app

我使用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');
}

有什么建议吗?

- 编辑

包括Dan在答案中提到的要点

➜  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');
}

9 个答案:

答案 0 :(得分:185)

有两种选择:

使用Imports

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

作为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');
}

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

通常这应该足够了。

使用public文件夹

如果出于某种原因,您希望使用构建管道,而是以“经典方式”进行,您可以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页面并将homepage字段设置为http://myuser.github.io/myproject,它将从/myproject提供。但是,fonts也位于public文件夹中,因此它们将从fonts相对地提供(http://mywebsite.com/fontshttp://myuser.github.io/myproject/fonts)。因此我们使用相对路径。

请注意,由于我们在此示例中避免使用构建管道,因此它不会验证文件是否确实存在。这就是为什么我不推荐这种方法。另一个问题是我们的index.css文件没有被缩小并且没有得到哈希值。因此,对于最终用户来说,它会变得更慢,并且您冒着浏览器缓存旧版本文件的风险。

使用哪种方式?

使用第一种方法(“使用进口”)。我只描述了第二个,因为那是你试图做的事情(根据你的评论判断),但它有很多问题,应该只是你解决某些问题时的最后手段。

答案 1 :(得分:7)

以下是一些方法:

1。导入字体

例如,要使用Roboto,请使用来安装软件包

yarn add typeface-roboto

npm install typeface-roboto --save

在index.js中:

import "typeface-roboto";

有npm软件包,可用于许多开源字体和大多数Google字体。您可以看到所有字体here。所有软件包均来自该project

2。对于第三方托管的字体

例如Google字体,您可以转到fonts.google.com,在其中找到可以放入public/index.html的链接

screenshot 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。使用网络字体加载程序包

使用安装软件包

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']
   }
});

答案 2 :(得分:2)

  1. 转到Google字体https://fonts.google.com/
  2. 选择您的字体,如下图所示:

enter image description here

  1. 复制该网址,然后将其粘贴到新标签中,您将获得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

答案 3 :(得分:1)

您可以使用WebFont模块,从而大大简化该过程。

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

答案 4 :(得分:0)

我在犯这样的错误。

@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);

答案 5 :(得分:0)

我花了整整一个上午的时间解决了类似的问题,然后才解决了这个堆叠问题。我在上面的答案中使用了丹的第一个解决方案作为起点。

问题

我有一个开发人员(在我的本地计算机上),暂存和生产环境。我的登台和生产环境位于同一台服务器上。

该应用通过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/css/中时,它是如何添加到/static/media/中的,以及如何复制目标文件夹。我排除了服务器配置是罪魁祸首。

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. homepage文件中删除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 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");
}

阅读材料

答案 6 :(得分:0)

链接到您的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>

答案 7 :(得分:0)

当对普通/斜体 font-style 使用不同的字体文件时,您指定 @font-face 的方式可能需要根据入口点而有所不同。 See my answer here

  1. 如果您选择将 css 文件直接链接到您的 public/index.html,那么您可以正常使用 font-face,使用一个 font-family 名称和不同的 font-style:< /li>
@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 文件进行捆绑,那么您需要为所有 font-family 字体使用不同的 italic 名称并使用 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;
}

答案 8 :(得分:-1)

您可以在不需要 CSS 的情况下使用 Web API FontFace 构造函数(也可以是 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);
});

Declare a file font.ts 与您的模块(仅限 TS):

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

如果 TS 找不到 FontFace 类型作为其仍在正式的 WIP,请将 this declaration 添加到您的项目中。它可以在您的浏览器中运行,但 IE 除外。