如何在NextJS中使用自托管字体?

29

使用NextJS加载字体

我阅读了关于如何在NextJS中使用自托管字体的不同话题。

当我执行以下操作时:

我得到了[等待]编译...

@font-face {
    font-family: 'montserrat';
    src: url('./mypath/Montserrat-Medium.woff2') format('woff2'),
        url('./mypath/Montserrat-Medium.woff') format('woff'),
        url('./mypath/Montserrat-Medium.ttf') format('truetype'),
        url('./mypath/Montserrat-Medium.svg#Montserrat-Medium') format('svg');
}

没有错误,或者只是编译...我读过 ( stackoverflow/57590195),它说我们应该使用静态路径,例如

@font-face {
    font-family: 'font';
    src: url('./static/fonts/Montserrat-Medium.woff2') format('woff2');
}

但是这种解决方案根本不起作用。它似乎工作得很好,因为错误(或引人注目的等待)停止了。但是如果你仔细看,你的字体并没有加载。

然后我尝试了fontfaceobserver,很快就明白了问题会是一样的。因为你必须使用font-face,而你无法在NextJS中使用它。

在我下载了next-font之后,我阅读了文档并查看了GitHub示例

这里是我的next.config.js,受到他们的启发。

const withSass = require('@zeit/next-sass');
const withCSS = require("@zeit/next-css");
const withFonts = require('next-fonts');

module.exports = withFonts(
    withCSS(
        withSass({
            enableSvg: true,
            webpack(config, options) {
                config.module.rules.push({
                    test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
                    use: {
                        loader: 'url-loader',
                        options: {
                            limit: 100000
                        }
                    }
                });
                return config;
            }
        })
    )
);

我的字体路径是 public/static/fonts

以下是我尝试使用它的方式。

...
function MainIndex() {
    ...
    return (
        <>
        ...
        <style jsx>{`
                @font-face {
                    font-family: 'Montserrat';
                    src: url('./static/fonts/Montserrat-Medium.ttf');
                }
                h1 {
                    font-family: 'Montserrat';
                }
        `}</style>
        </>
    )
}
...

我发现的解决方案

在GitHub上阅读更多问题

编辑:

我尝试了适应Jesper We的方法。这里

我创建了/public/static/fonts/fonts.css/public/fonts/allMyfont.ttf,然后我在_var.scss中导入以使用sass变量@import "/public/static/fonts/fonts.css";导入style.scss我的var $font和import "my/path/style.scss"到我的index.js(编译永远失败)

之后,我尝试了一个更接近的方式,仍然是/public/static/fonts/fonts.css,并将我的字体放在同一个文件夹中。然后在我的index.js中,但那个什么也没做。

这里是在线代码CodeSandBox


2
这里需要注意的是,不应在Web上使用TTF文件,因为它们是未经优化的文件。如果你有一个TTF文件,可以使用Google的woff2命令行工具(其中包含一个名为woff2_compress的工具)将TTF文件转换为WOFF2压缩文件,以便在你的网站上使用。 - vhs
我在搜索此主题时犯了一个愚蠢的错误:我的字体文件扩展名是大写的(.TTF 而非 .ttf) ‍♂️ - glimmbo
6个回答

31

这是我通常做的事情:

  1. 将字体放在public/static文件夹中的某个位置

  2. 在与字体相同的文件夹中放置一个CSS文件,其中声明了字体

CSS文件示例 /public/fonts/style.css

@font-face {
    font-family: 'Italian No1';
    src: url('ItalianNo1-Black.eot');
    src: url('ItalianNo1-Black.eot?#iefix') format('embedded-opentype'), url('ItalianNo1-Black.woff2') format('woff2'), url('ItalianNo1-Black.woff') format('woff');
    font-weight: 900;
    font-style: normal;
}

[更新] 对于最近的NextJS版本,正确导入CSS文件的位置是在_app.js中的import语句中(请参见文档)


旧版答案:

_document.jsdocs)中导入此CSS:

render() {
    return (
        <Html>
            <Head>
                <link href="/fonts/style.css" rel="stylesheet"/>
            </Head>

            <body>
                <Main/>
                <NextScript/>
            </body>
        </Html>
    )
}

是否应该将其命名为_document.js文件?在page/_document.js中吗?因为我的架构不同,我尝试适应你的做法,但在这里无法工作:/ 我会编辑我的问题。 - crg
pages/_document.js 是正确的路径。我在答案中添加了相关文档的链接。 - Jesper We
非常感谢您! - iji
在 _document.js 中使用 link 标签并不推荐,因为它可能会对应用程序中的 CSS 资源加载产生负面影响。Next.js 的文档中提到了这一点,https://nextjs.org/docs/messages/no-css-tags。如果你运行 eslint,它会发出警告。 - ZR87

19

小贴士:现在你不需要提供多个字体文件,只需使用可变字体一个文件即可,因为它被广泛支持。此外,新的字体格式woff2具有更好的压缩比,并且再次广泛支持

  1. 将字体文件放入/public/fonts/文件夹中

  2. 将其添加到_document.tsx文件中,以便为所有页面获取它:

export default class MyDocument extends Document {
  render(): JSX.Element {
    return (
      <Html>
        <Head>
          <link
            rel="preload"
            href="/fonts/inter-var-latin.woff2"
            as="font"
            type="font/woff2"
            crossOrigin="anonymous"
          />
        </Head>
        ...
  1. 在全局CSS文件中提及:
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-weight: 100 900;
    font-display: optional;
    src: url(/fonts/inter-var-latin.woff2) format("woff2");
  }
  1. 告诉浏览器将此字体文件缓存长时间(约1年),以避免在后续的网站访问中进行不必要的重新下载。
    next.config.json中添加头信息:
module.exports = {
  async headers() {
    return [
      {
        source: "/fonts/inter-var-latin.woff2",
        headers: [
          {
            key: "Cache-Control",
            value: "public, max-age=31536000, immutable",
          },
        ],
      },
    ];
  },
};

参考资料:https://gourav.io/blog/nextjs-cheatsheet#add-custom-fonts


不错!顺便澄清一下,似乎 next.config.js 中的 Cache-Controls 标头已不再有效:https://nextjs.org/docs/api-reference/next.config.js/headers#cache-control - Alejandro Corredor
此外,需要澄清的是,可变字体并不总是首选。例如,如果您只需要一种或两种字体变体,则最好仅包含特定的字重。例如:Inter variable 大约为 800kb。如果您只使用常规和粗体,则大约为 600kb。这里的 200kb 差异很大。 - Pawel
@AlejandroCorredor 看起来运行良好 https://cln.sh/OMrxph - GorvGoyl

15

我已经尝试了最新版本的next.js "next": "10.0.8"

将所有字体添加到public/fonts文件夹中,并在globals.css中使用字体。

我认为您在字体中使用的路径可能不正确,但我不确定代码结构。

 @font-face {
  font-family: 'Open Sans';
  src: url('../public/fonts/OpenSans-Light.eot');
  src: url('../public/fonts/OpenSans-Light.eot?#iefix') format('embedded-opentype'),
  url('../public/fonts/OpenSans-Light.woff2') format('woff2'),
  url('../public/fonts/OpenSans-Light.woff') format('woff'),
  url('../public/fonts/OpenSans-Light.ttf') format('truetype');
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}

之后您可以使用它 font-family: 'Open Sans'

如果您想了解更多相关信息,请参阅相关博客文章


3
将/fonts/OpenSans.otf目录移动到public/fonts/OpenSans.otf。对我来说有效。
现在我可以使用这行代码在任何地方:
@font-face {
      font-family: 'OpenSans';
        src: url('/fonts/OpenSans.otf') format('opentype');
        font-weight: normal;
        font-style: normal;
    }

1

1-在你的Next.js项目的“public”目录下创建一个名为“fonts”的新文件夹。

2-将字体文件添加到“fonts”目录中。例如,如果你有一个名为“myfont.ttf”的字体文件,你应该将它添加到“fonts”目录中,路径为:“public/fonts/myfont.ttf”

3-globals.css

@font-face {
  font-family: 'MyFont';
  src: url('/fonts/myfont.ttf') format('truetype');
  font-weight: normal;
  font-style: normal;
}

.myFontFamily {
  font-family: 'MyFont', sans-serif;
}

4-index.jsx

<div className="myFontFamily">Hello World!</div>

0
在使用tailwindcss的v12.0.4版本中,我不得不尝试几个fs更改,但最终采用了以下方法。此外,我还同时使用了自定义字体和谷歌字体。
您也可以测试内联全局CSS,而无需使用tailwind。
# _app.js
<div style={{ fontFamily: "Inter"}}>
    <Component {...pageProps} />
</div>

import '../public/styles.css' # 在 public/ 目录外无法正常工作

# styles.css
# font files are in the same directory
@font-face {
    font-family: 'Avenir';
    src: url('avenir/avenir-light.woff') format('woff');
    font-weight: 100;
    font-style: normal;
}

# tailwind.config.js
    theme: {
        extend: {
            fontFamily: {
                sans: ['Avenir', 'Inter', ...defaultTheme.fontFamily.sans],
                title: ['Avenir', 'Inter', ...defaultTheme.fontFamily.sans]
            }
        }
    },

# _document.js
<Head>
    <link
        href="https://fonts.googleapis.com/css2?family=Inter&display=optional"
        rel="stylesheet"
    />
</Head>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接