Skip to main content

@remotion/layout-utils 的最佳实践

请注意以下几点,以确保在使用 @remotion/layout-utils 包时测量正确。

🌐 Take note of the following points to ensure correct measurements when using the @remotion/layout-utils package.

这些提示适用于 measureText()fitText()fillTextBox()

🌐 These tips apply to all of measureText(), fitText(), and fillTextBox().

等到字体加载完成

🌐 Wait until the font is loaded

只有在字体加载完成后才调用 measureText()。这适用于 Google 字体(下面示例)或任何其他字体加载机制。

🌐 Only call measureText() after the font is loaded. This applies to Google Fonts (example below) or any other font loading mechanism.

包含 useEffect 的示例

🌐 Example with useEffect

MyComp.tsx
import {useState, useEffect} from 'react'; import {Dimensions, measureText} from '@remotion/layout-utils'; import {loadFont, fontFamily} from '@remotion/google-fonts/Inter'; const {waitUntilDone} = loadFont('normal'); const MyComp: React.FC = () => { const [dimensions, setDimensions] = useState<Dimensions | null>(null); useEffect(() => { // Wait until the font is loaded before measuring text waitUntilDone().then(() => { const measurement = measureText({ fontFamily: fontFamily, fontSize: 14, fontWeight: '400', text: 'Hello world', }); // We don't need to use delayRender() here, because // font loading from @remotion/google-fonts is already wrapped in it setDimensions(measurement); }); }, []); return null; };

使用高阶组件的示例

🌐 Example with high-order component

以下逻辑借鉴自 Remotion Recorder。 它通过暴露一个高阶组件来保持代码整洁,该组件只有在字体加载完成时才会挂载其子组件。

🌐 This following logic is borrowed from the Remotion Recorder.
It keeps the code clean by exposing a high-order component which only mounts its children when the font is loaded.

定义了一个加载一些字体的文件:

🌐 A file is defined which loads some fonts:

fonts.ts
import {fontFamily as regularFont, loadFont as loadRegular} from '@remotion/google-fonts/Inter'; import {fontFamily as monospaceFont, loadFont as loadMonospace} from '@remotion/google-fonts/RobotoMono'; import {cancelRender, continueRender, delayRender} from 'remotion'; const regular = loadRegular(); const monospace = loadMonospace(); export const waitForFonts = async () => { await regular.waitUntilDone(); await monospace.waitUntilDone(); }; const delay = delayRender('Loading fonts'); waitForFonts() .then(() => continueRender(delay)) .catch((err) => cancelRender(err));

然后定义了一个高阶组件,只有在字体加载完成时才渲染它的子组件:

🌐 Then a higher order component is defined which only renders it's children when the font is loaded:

WaitForFonts.tsx
import React, {useEffect, useState} from 'react'; import {cancelRender, continueRender, useDelayRender} from 'remotion'; import {waitForFonts} from './fonts'; export const WaitForFonts: React.FC<{ children: React.ReactNode; }> = ({children}) => { const [fontsLoaded, setFontsLoaded] = useState(false); const {delayRender, continueRender} = useDelayRender(); const [handle] = useState(() => delayRender('Waiting for fonts to be loaded')); useEffect(() => { if (fontsLoaded) { return; } waitForFonts() .then(() => { setFontsLoaded(true); }) .catch((err) => { cancelRender(err); }); }, [fontsLoaded, handle, continueRender, delayRender]); useEffect(() => { if (fontsLoaded) { continueRender(handle); } }, [continueRender, fontsLoaded, handle]); if (!fontsLoaded) { return null; } return <>{children}</>; };

然后该组件可以封装任何调用文本测量 API 的其他组件:

🌐 Then the component can be wrap any other component that calls text measurement APIs:

MyComp.tsx
import React from 'react'; import {regular} from './fonts'; import {WaitForFonts} from './WaitForFonts'; import {measureText} from '@remotion/layout-utils'; const MyCompInner: React.FC = () => { // Safe to call measureText() here const measurement = measureText({ fontFamily: regular, fontSize: 14, fontWeight: '400', text: 'Hello world', }); return null; }; export const MyComp: React.FC = () => { return ( <WaitForFonts> <MyCompInner /> </WaitForFonts> ); };

使用 validateFontIsLoaded 选项v4.0.136

🌐 Use the validateFontIsLoaded optionv4.0.136

validateFontIsLoaded: true 传递给 measureText()fitText()fillTextBox() 中的任意一个,以验证你传递的字体家族是否已实际加载。

🌐 Pass validateFontIsLoaded: true to any of measureText(), fitText(), and fillTextBox() to validate that the font family you passed is actually loaded.

这将使用备用字体进行第二次测量,如果测量结果相同,它就会假定使用了备用字体并抛出错误。

🌐 This will take a second measurement with the fallback font and if it produces the same measurements, it assumes the fallback font was used and will throw an error.

note

在 Remotion v5 中,这将成为默认设置。

匹配所有字体属性

🌐 Match all font properties

在测量文本时,确保所有字体属性与你将在视频中使用的字体属性匹配。
这包括 fontFamilyfontSizefontWeightletterSpacingfontVariantNumeric

🌐 When measuring text, ensure that all font properties match the ones you are going to use in your video.
This includes fontFamily, fontSize, and fontWeight, letterSpacing and fontVariantNumeric.

你可以创建可重用的变量,在测量函数和实际组件中都引用它们。

🌐 You could make reusable variables that you reference in both the measuring function and the actual component.

Using variables for font properties
import {measureText} from '@remotion/layout-utils'; const text = 'Hello world'; const fontFamily = 'Inter'; const fontWeight = 'bold'; const fontSize = 16; // Use the variable in the measurement function: measureText({ text, fontFamily, fontWeight, fontSize, }); // As well as in markup <div style={{fontFamily, fontWeight, fontSize}}>{text}</div>;

注意边框和内边距

🌐 Be aware of borders and padding

在一个单词中添加 paddingborder 会影响测量结果。 完全避免使用 padding,并使用单词之间的自然间距。 不要使用 border,而是使用 outline 在文本外添加一行而不影响布局。

🌐 Adding a padding or a border to a word will skew the measurements.
Avoid using padding altogether and use the natural spacing between words.
Instead of border, use an outline to add a line outside the text without affecting its layout.

空白

🌐 Whitespace

在测量时,布局工具将使用应用了 display: inline-blockwhite-space: pre<span> 来换行文本。 这也会测量空白字符的宽度。

🌐 When measuring, the Layout utils will wrap the text in a <span> with display: inline-block and white-space: pre applied.
This will also measure the width of the whitespace characters.

也将这两个 CSS 属性添加到你的标记中,以使其与测量值匹配。

🌐 Add those two CSS properties to your markup as well to match it with the measurements.

服务器端渲染

🌐 Server-side rendering

布局工具需要在浏览器中运行。
如果你在将进行服务器端渲染的组件中使用它们,那么我们建议你在 useEffect 中调用这些函数,就像本页第一个示例中那样。

🌐 The layout utilities need to be run in a browser.
If you are using them in a component that will be server-side rendered, then we recommend you call the functions in a useEffect, like on the first example on this page.