【问题标题】:Flash Of Unstyled Text (FOUT) on reload using next.js and styled components使用 next.js 和样式化组件重新加载时的 Flash Of Unstyled Text (FOUT)
【发布时间】:2020-07-05 13:37:42
【问题描述】:

我正在使用带有 next.js 的样式化组件中的全局样式,每次重新加载页面时,我都可以看到字体闪烁。

我的字体文件在public/fonts/Inconsolata

我在频谱聊天中到处寻找,next.js github问题,但似乎找不到任何解决方案。

pages/index.js

import styled from 'styled-components';

const H1 = styled.h1`
  font-family: 'Inconsolata Bold';
  font-weight: 700;
  color: #000;
`;

const index = () => {
  return (
    <div>
      <H1>font flashes</H1>
    </div>
  );
};

export default index;

pages/_app.js

import App from 'next/app';
import React from 'react';

import GlobalStyle from '../src/style/globalStyle';

export default class MyApp extends App {
  render() {
    const { Component, pageProps } = this.props;
    return (
      <>
        <GlobalStyle />
        <Component {...pageProps} />
      </>
    );
  }
}

pages/_document.js

import Document from 'next/document';
import { ServerStyleSheet } from 'styled-components';

export default class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: App => props => sheet.collectStyles(<App {...props} />)
        });

      const initialProps = await Document.getInitialProps(ctx);
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        )
      };
    } finally {
      sheet.seal();
    }
  }
}

style/globalStyle.js

import { createGlobalStyle } from 'styled-components';

const globalStyle = createGlobalStyle`
  @font-face {
    font-family: 'Inconsolata';
    src:  url('./fonts/Inconsolata/Inconsolata-Regular.woff2') format('woff2'),
          url('./fonts/Inconsolata/Inconsolata-Regular.woff') format('woff');
    font-weight: 400;
    font-style: normal;
    font-display: fallback;
  }
  @font-face {
    font-family: 'Inconsolata Bold';
    src:  url('./fonts/Inconsolata/Inconsolata-Bold.woff2') format('woff2'),
          url('./fonts/Inconsolata/Inconsolata-Bold.woff') format('woff');
    font-weight: 700;
    font-style: bold;
    font-display: fallback;
  }
`;

export default globalStyle;

【问题讨论】:

  • 我也有同样的问题
  • 你能解决吗?

标签: reactjs next.js server-side-rendering styled-components vercel


【解决方案1】:

更新:

Next.js 发布了一个名为 Automatic Webfont Optimization 的新功能。

只需包含您的字体(目前仅适用于 Google 字体),它将在构建时作为原始 css 包含在内。

// Before
<link
  href="https://fonts.googleapis.com/css2?family=Inter"
  rel="stylesheet"
/>

// After
<style data-href="https://fonts.googleapis.com/css2?family=Inter">
  @font-face{font-family:'Inter';font-style:normal.....
</style>

查看 Next.js 人员如何在他们的网站上处理它,该网站是开源的,可以在 here 找到。看看,它对我有用。

  1. 通过预加载链接将您使用的字体导入 css @font-face

    <link
        rel="preload"
        href="/assets/my-font.woff2"
        as="font"
        type="font/woff2"
    />
    
  2. 您的字体声明应该在 SSR HTML 页面上,因此请使用&lt;style jsx global /&gt; 将其包含在您的页面中。可以是外部文件,也可以直接在style元素中。

【讨论】:

  • nextjs 网站已经没有了,至少我找不到了
【解决方案2】:

NextJS 12、Google Fonts 和 SCSS 模块也有类似的问题。

我的部分解决方案是

  1. “预加载”任何 CSS 文件中任何 @font-face 规则中请求的资源 - 更急切地加载字体
  2. 设置font-display: optional - 如果字体没有及时加载,告诉 CSS 使用回退

这意味着没有 Flash Of Unstyled Text (FOUT),但在较慢的连接上,将在首次加载时使用备用字体。

   <head>
      <link rel="preconnect" href="https://fonts.googleapis.com" />
      <link
        rel="preload"
        href="https://fonts.gstatic.com/s/inconsolata/v21/QlddNThLqRwH-OJ1UHjlKENVzkWGVkL3GZQmAwLyya15IDhunA.woff2"
        as="font"
        type="font/woff2"
        crossOrigin=""
      />
      <link
        rel="preload"
        href="https://fonts.gstatic.com/s/inconsolata/v21/QlddNThLqRwH-OJ1UHjlKENVzkWGVkL3GZQmAwLyx615IDhunJ_o.woff2"
        as="font"
        type="font/woff2"
        crossOrigin=""
      />
       // CSS file with @font-face rules and font-display: optional
      <link
        href="https://fonts.googleapis.com/css2?family=Inconsolata:wght@300;400;700&display=optional"
        rel="stylesheet"
      />
</head>

在此示例中,最后一个 link 元素请求一个 CSS 文件,该文件包含许多 @font-face 规则,带有 src 声明和 url() 值。

如果 url() 函数中的资源没有预加载到头部,那么在解析 CSS 之前不会请求它们。

我认为这就是导致 FOUT 的原因。

通过包含&lt;link rel="preload" src="..."/&gt; 元素可以更快地加载字体。

setting font-display: optional 告诉浏览器,如果字体没有及时加载,则使用回退。

我正在开发的网站:Soundboard

【讨论】:

  • 谢谢!这是唯一经过大量搜索后对我有用的设置!
【解决方案3】:

我遇到了同样的问题,经过数小时尝试不同的方法后,npm package fontfaceobserver 为我解决了这个问题。

使用该包,您可以告诉您的应用仅在加载字体后进行渲染,从而避免像这样的 FOUT:

import FontFaceObserver from "fontfaceobserver";

const font = new FontFaceObserver("Inconsolata");

font.load().then(()=> {
  ReactDOM.render(<App />,document.getElementById("root"));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-16
    • 1970-01-01
    • 2012-01-04
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多