使用 next.js 和样式化组件重新加载时的 Flash Of Unstyled Text (FOUT)
Posted
技术标签:
【中文标题】使用 next.js 和样式化组件重新加载时的 Flash Of Unstyled Text (FOUT)【英文标题】:Flash Of Unstyled Text (FOUT) on reload using next.js and styled components 【发布时间】: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;
【问题讨论】:
我也有同样的问题 你能解决吗? 【参考方案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-facefont-family:'Inter';font-style:normal.....
</style>
查看 Next.js 人员如何在他们的网站上处理它,该网站是开源的,可以在 here 找到。看看,它对我有用。
通过预加载链接将您使用的字体导入 css @font-face
<link
rel="preload"
href="/assets/my-font.woff2"
as="font"
type="font/woff2"
/>
您的字体声明应该在 s-s-r html 页面上,因此请使用<style jsx global />
将其包含在您的页面中。可以是外部文件,也可以直接在style
元素中。
【讨论】:
nextjs 网站已经没有了,至少我找不到了【参考方案2】:NextJS 12、Google Fonts 和 SCSS 模块也有类似的问题。
我的部分解决方案是
-
“预加载”任何 CSS 文件中任何
@font-face
规则中请求的资源 - 更急切地加载字体
设置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 的原因。
通过包含<link rel="preload" src="..."/>
元素可以更快地加载字体。
而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"));
【讨论】:
以上是关于使用 next.js 和样式化组件重新加载时的 Flash Of Unstyled Text (FOUT)的主要内容,如果未能解决你的问题,请参考以下文章
Next.js Router.push() 自动重新加载页面