imgrender

文字排版与字体

字体管理和高级文本渲染

字体

imgrender 预设了常用字体,也支持在请求 API 时自定义字体

系统预设字体

imgrender 内预设了以下字体,这些字体可免费商用。

Font FamilyGeneral Font FamilySupported Font WeightSupported Font Style
AlibabaPuHuiTisans-serif100 300 400 500 700 900normal
Alibaba Sans KRsans-serif100 300 400 500 700 900normal
Source Han Serif CNserif200 300 400 500 600 700 900normal
Source Han Serif JPserif200 300 400 500 600 700 900normal
Source Han Serif KRserif200 300 400 500 600 700 900normal
Source Han Sans CNsans-serif100 300 350 400 500 700 900normal
Source Han Sans TWsans-serif100 300 350 400 500 700 900normal
Source Han Sans JPsans-serif100 300 350 400 500 700 900normal
Source Han Sans KRsans-serif100 300 350 400 500 700 900normal
Geistsans-serif100 200 300 400 500 600 700 800 900normal oblique
Geist Monomonospace100 200 300 400 500 600 700 800 900normal
Twemojiemoji不适用不适用

关于字重和字体样式

字重说明:

  • 100 - Thin(极细)
  • 200 - ExtraLight(特细)
  • 300 - Light(细)
  • 400 - Regular(常规)
  • 500 - Medium(中等)
  • 600 - SemiBold(半粗)
  • 700 - Bold(粗)
  • 800 - ExtraBold(特粗)
  • 900 - Black/Heavy(黑体/特粗)

关于斜体:

  • 中日韩(CJK)字体(如思源宋体、思源黑体、阿里巴巴普惠体)通常不包含真正的斜体(italic)字形
  • Geist 字体的 oblique 样式是通过机械倾斜正体字实现的伪斜体
  • 如需中文斜体效果,可使用 CSS 的 transform: skewX()font-style: oblique 实现

字体来源

  • AlibabaPuHuiTi / Alibaba Sans KR - 阿里巴巴设计团队出品,GitHub
  • Source Han Serif - Adobe 开源字体(思源宋体),GitHub
  • Source Han Sans - Adobe 开源字体(思源黑体),GitHub
  • Geist / Geist Mono - Vercel 出品,官网 / GitHub
  • Twemoji - Twitter 开源 Emoji 字体,GitHub

使用字体

使用通用字体名:

<div style={{ fontFamily: 'sans-serif' }}>Hello imgrender</div>

会使用 sans-serif 字体。由于存在多个 sans-serif 字体,具体使用到的字体遵循字体回退机制

<div style={{ fontFamily: 'serif' }}>Hello imgrender</div>

会使用 serif 字体。由于存在多个 serif 字体,具体使用到的字体遵循字体回退机制

<div tw="font-sans">Hello imgrender</div>

会使用 sans-serif 字体。由于存在多个 sans-serif 字体,具体使用到的字体遵循字体回退机制

<div tw="font-serif">Hello imgrender</div>

会使用 serif 字体。由于存在多个 serif 字体,具体使用到的字体遵循字体回退机制

使用指定字体:

<div style={{ fontFamily: 'Source Han Serif CN' }}>Hello imgrender</div>

指定使用 Source Han Serif CN 字体。

<div tw="font-[Source_Han_Serif_CN]">Hello imgrender</div>

指定使用 Source Han Serif CN 字体。

TailwindCSS 对 Font Family 中空格的特殊处理

TailwindCSS 中,空格需要使用下划线 _ 代替。

例如,指定使用 Source Han Serif CN 字体,应使用 font-[Source_Han_Serif_CN],而不是 font-[Source Han Serif CN]

字体回退机制

字体回退(Font Fallback)机制用于在首选字体不可用或不包含所需字符时,自动选择替代字体。imgrender 根据以下规则处理字体回退:

未指定字体时的回退

当没有明确指定 font-family 时,imgrender 会按照系统预设字体表格的顺序依次尝试,直到找到能够渲染当前字符的字体:

// 未指定 font-family
<div>Hello 世界 🎉</div>

渲染过程:

  1. Hello - 尝试 AlibabaPuHuiTi,包含拉丁字母,直接渲染
  2. 世界 - AlibabaPuHuiTi 包含中文字符,直接渲染
  3. 🎉 - AlibabaPuHuiTi 不包含 emoji,按表格顺序查找,最终由 Twemoji 渲染

完整回退顺序(按表格从上到下):

AlibabaPuHuiTi → Alibaba Sans KR → Source Han Serif CN → Source Han Serif JP →
Source Han Serif KR → Source Han Sans CN → Source Han Sans TW → Source Han Sans JP →
Source Han Sans KR → Geist → Geist Mono → Twemoji

默认字体的选择

由于 AlibabaPuHuiTi 位于表格首位,且包含中日韩文字和拉丁字母,大多数文本在未指定字体时会直接使用 AlibabaPuHuiTi 渲染。这意味着:

  • 中文、英文、数字默认使用 AlibabaPuHuiTi(无衬线黑体风格)
  • Emoji 默认使用 Twemoji
  • 如需衬线字体或特定风格,请显式指定 font-family

使用通用字体名时的回退

当使用通用字体名(如 sans-serifserifmonospaceemoji)时,imgrender 会按照系统预设字体表格中的顺序,从上到下查找该类别的第一个可用字体:

通用字体名回退顺序(按表格顺序)
sans-serifAlibabaPuHuiTi → Alibaba Sans KR → Source Han Sans CN → Source Han Sans TW → Source Han Sans JP → Source Han Sans KR → Geist
serifSource Han Serif CN → Source Han Serif JP → Source Han Serif KR
monospaceGeist Mono
emojiTwemoji

示例:

// 使用 sans-serif 时,会优先使用 AlibabaPuHuiTi
<div style={{ fontFamily: 'sans-serif' }}>你好世界</div>

// 使用 serif 时,会优先使用 Source Han Serif CN
<div style={{ fontFamily: 'serif' }}>你好世界</div>

字符缺失时的回退

当渲染某个字符时,如果当前字体不包含该字符的字形(glyph),系统会按以下顺序查找:

  1. 检查字体列表中的下一个字体 - 如果 font-family 指定了多个字体,依次尝试
  2. 检查同类别的其他字体 - 在同 General Font Family 的预设字体中查找
  3. 跨类别查找 - 尝试其他类别的字体
  4. 使用后备字体 - 最后使用系统默认后备字体

示例:

// 混合文本的回退过程
<div style={{ fontFamily: 'Geist' }}>Hello 世界 🎉</div>

渲染过程:

  1. Hello - Geist 包含拉丁字母,直接渲染
  2. 世界 - Geist 不包含中文,回退到 AlibabaPuHuiTi(首个 sans-serif 中文字体)
  3. 🎉 - 所有文本字体都不包含 emoji,回退到 Twemoji

自定义字体回退列表

你可以在 font-family 中指定多个字体,用逗号分隔,实现自定义的回退顺序:

<div style={{ fontFamily: 'Geist, Source Han Sans CN, sans-serif' }}>
  Hello 世界
</div>

回退顺序:

  1. 优先使用 Geist 渲染拉丁字母
  2. 中文回退到 Source Han Sans CN
  3. 最后使用系统默认 sans-serif
<div tw="font-[Geist,Source_Han_Sans_CN,sans-serif]">Hello 世界</div>

TailwindCSS 中,字体名称之间的空格需要用下划线替代,但逗号后的空格可以保留。

最佳实践

  1. 指定回退字体 - 始终在 font-family 末尾添加通用字体名作为保底
  2. 考虑语言特性 - 混合多语言内容时,明确指定各语言的回退字体
  3. Emoji 处理 - 如需精确控制 emoji 渲染,在字体列表末尾添加 emoji
<div style={{ fontFamily: 'Geist, Source Han Sans CN, Twemoji, sans-serif' }}>
  Hello 世界 🎉
</div>

文字排版

空白控制

默认情况下,imgrender 遵循 HTML 标准的默认空白规则:合并连续空白(空格、制表符、换行符均被合并为一个空格)、忽略行首尾空白 以及自动换行。

你也可以使用 white-space 属性来控制空白的渲染规则:

属性值合并空白符保留换行符自动换行说明
normal默认行为,连续空白符合并为一个空格,换行符也被合并,文本自动换行
nowrap合并空白符和换行符,但禁止自动换行,文本在同一行内显示
pre保留所有空白符和换行符,禁止自动换行,行为类似 <pre> 元素
pre-line合并空白符但保留换行符,文本自动换行,源码中的换行会被保留
pre-wrap保留所有空白符和换行符,同时允许自动换行,适合显示格式化代码
break-spacespre-wrap 相同,但行末的空格和换行符也会占用空间并影响布局

使用示例

保留源码中的换行和缩进:

<div style={{ whiteSpace: 'pre-wrap' }}>
  {`第一行文字
    第二行有缩进
第三行无缩进`}
</div>

禁止文本换行:

<div style={{ whiteSpace: 'nowrap' }}>
  这段文字不会自动换行,即使容器宽度不够
</div>

保留源码中的换行和缩进:

<div tw="whitespace-pre-wrap">
  {`第一行文字
    第二行有缩进
第三行无缩进`}
</div>

禁止文本换行:

<div tw="whitespace-nowrap">这段文字不会自动换行,即使容器宽度不够</div>

关于换行符

在 JSX 中,直接在字符串中输入换行符可能不太方便。可以使用模板字符串(反引号)来保留源码中的换行,或者使用 {'\n'} 显式插入换行符。

换行

CSS 的 text-wrap 属性用于控制元素内的文本换行方式。imgrender 支持以下值:

属性值说明
wrap默认值,文本在行尾自动换行,受 word-breakoverflow-wrap 等属性影响
nowrap禁止文本换行,所有文本将在同一行内显示(效果等同于 white-space: nowrap
balance平衡换行,自动调整换行位置使每行的字符数尽可能相近,适合标题、段落等短文本
pretty美观换行,与 balance 类似但更注重排版美观,可能会调整连字符断字等,适合长段落,计算成本更高

balance vs pretty

  • balance 更适合标题、卡片内容等短文本,换行决策较快
  • pretty 更适合长段落,会考虑更多排版因素(如避免孤词),但渲染开销更大

使用示例

平衡换行(适合标题):

<h1 style={{ textWrap: 'balance' }}>
  This is a long title that will be wrapped evenly across lines
</h1>

美观换行(适合段落):

<p style={{ textWrap: 'pretty' }}>
  This is a long paragraph text that benefits from prettier line breaking with
  better typography considerations like preventing orphans.
</p>

禁止换行:

<div style={{ textWrap: 'nowrap' }}>这段文本不会换行</div>

平衡换行(适合标题):

<h1 tw="text-wrap-balance">
  This is a long title that will be wrapped evenly across lines
</h1>

美观换行(适合段落):

<p tw="text-wrap-pretty">
  This is a long paragraph text that benefits from prettier line breaking with
  better typography considerations like preventing orphans.
</p>

禁止换行:

<div tw="text-wrap-nowrap">这段文本不会换行</div>

与 white-space 的关系

text-wrap: nowrapwhite-space: nowrap 效果相同。两者的区别在于:

  • white-space 主要控制空白符的处理方式
  • text-wrap 专注于换行行为控制

在需要禁止换行但保留空白符的场景下,建议使用 text-wrap: nowrap 配合 white-space: pre 等值。

文字溢出省略

当容器空间不足以显示完整文本时,可以使用 text-overflow 属性控制溢出文本的显示方式。

text-overflow 属性

属性值说明
clip默认值,直接裁剪溢出文本,不显示任何提示
ellipsis在溢出文本末尾显示省略号 ...
string使用自定义字符串代替省略号(部分浏览器支持有限)

生效条件

text-overflow 生效需要同时满足以下条件:

  1. 元素设置 overflow: hidden(或 overflow: scroll / auto
  2. 元素有明确的宽度限制(如 widthmax-widthflex-shrink
  3. 对于单行省略:设置 white-space: nowraptext-wrap: nowrap

单行文本省略

<div
  style={{
    width: '200px',
    overflow: 'hidden',
    whiteSpace: 'nowrap',
    textOverflow: 'ellipsis',
  }}
>
  这是一段很长很长的文本,超出容器宽度时会显示省略号
</div>
<div tw="w-48 truncate">这是一段很长很长的文本,超出容器宽度时会显示省略号</div>

TailwindCSS 的 truncate 工具类同时设置了 overflow: hiddentext-overflow: ellipsiswhite-space: nowrap

多行文本省略

对于多行文本的省略,使用 -webkit-line-clamp 属性限制显示行数:

<div
  style={{
    width: '300px',
    display: '-webkit-box',
    WebkitBoxOrient: 'vertical',
    WebkitLineClamp: 3,
    overflow: 'hidden',
  }}
>
  这是一段很长很长的文本,当超过三行时会被截断并显示省略号。
  多行省略在实际开发中非常常见,比如文章摘要、商品描述等场景。 imgrender
  会自动处理这些样式,确保渲染效果符合预期。
</div>
<div tw="w-72 line-clamp-3">
  这是一段很长很长的文本,当超过三行时会被截断并显示省略号。
  多行省略在实际开发中非常常见,比如文章摘要、商品描述等场景。 imgrender
  会自动处理这些样式,确保渲染效果符合预期。
</div>

TailwindCSS 提供 line-clamp-{n} 工具类(n 为 1-6),配合 overflow: hidden 使用。

imgrender 的特殊处理

在 imgrender 中,使用 line-clamp 时无需手动设置 display: -webkit-box 等属性,imgrender 会自动识别并处理。你也可以使用简化的写法:

<div style={{ lineClamp: 3, overflow: 'hidden' }}>多行文本内容...</div>

On this page