将编辑器 CSS 导出为 DOCX 样式
Beta 功能
本页上的 API 和属性映射正在逐步稳定,但在正式可用之前仍可能继续 调整。如果你依赖此功能,请固定精确的包版本,并在采用之前阅读 不会起作用的内容 一节。
这会做什么
从 Tiptap 导出到 DOCX 时,通常会把文档的 节点和标记属性 写入到每个段落、文本片段和单元格的内联样式中。结果会得到一个 DOCX 文件,其中每个元素都携带自己的一份 fontSize、color 和间距:冗长、重复、视觉上相同,但结构上并不理想。
此功能让你把编辑器的 样式表 作为唯一可信来源。你可以提供 CSS 规则(显式提供,或让我们从浏览器中提取),导出时我们会把这些规则编译成 DOCX 样式定义:也就是 Word 作为自身可信来源所使用的命名条目。导出的 DOCX 会拥有一个完整的样式目录,Word 用户只需编辑一次,就能改变所有使用该样式的段落外观。
与 导入时的 CSS 注入 配合使用后,你就能为文档的 样式层 建立一条往返路径,而与 内容层 分离。
第二个示例演示浏览器提取(browser-extraction)变体:
安装
npm i @tiptap-pro/extension-export-docx@^0.16.0工作原理
三个步骤:
- 收集 CSS。 导出器会从两个可能来源读取你的样式(你可以任意选择其一或同时使用两者):
- 你在
configure()中传入的显式styles对象 - 浏览器的实时样式表(如果
extractFromDocument: true),作用域限定在你的编辑器根节点(editor root)
- 你在
- 编译每个选择器。 编译器在一个固定映射(import 侧相同的 16 个选择器)中查找每个选择器,把每个 CSS 属性转换为它的 DOCX 等效项,并丢弃那些无法映射的属性。
- 合并到样式目录(styles catalog)。 编译后的 DOCX 样式片段会合并进导出选项的样式目录,然后交给 DOCX 写入器(writer)。
import { ExportDocx } from '@tiptap-pro/extension-export-docx'
ExportDocx.configure({
cssStyles: {
styles: {
h1: { fontSize: '32px', fontWeight: 'bold', color: '#1a1a1a' },
p: { fontSize: '16px', lineHeight: 1.5, marginTop: '0pt', marginBottom: '8pt' },
blockquote: { fontStyle: 'italic', color: '#555' },
},
// 可选:也从实时浏览器样式表中提取规则
extractFromDocument: true,
// 可选:用于 rem/em 解析的基准
baseFontSize: 16,
},
})当 extractFromDocument: true 时,导出器会遍历 document.styleSheets,找到在你的编辑器根节点作用域下匹配这 16-selector 映射的规则,并将它们与任何显式 styles 合并。逐属性而言,后者/显式样式优先(wins per-property)。
适用项
选择器(16): 与导入侧相同。
p, h1–h6, blockquote, ul li, ol li, strong, em, u, s, a, code
CSS 属性。 每个选择器都可以包含以下任意子集。未列出的属性在导出时会跳过,并在导出过程中输出 console.warn。
fontSize: 转换为 half-points(DOCXw:sz)color: 映射到 DOCXw:color(十六进制)fontFamily: 映射到 DOCXw:rFontsfontWeight:bold切换w:bfontStyle:italic切换w:itextDecoration:underline→w:u,line-through→w:strikebackgroundColor: 映射到 DOCXw:shd填充letterSpacing: 导出时支持(导入时不提取)textAlign: 映射到 DOCXw:jc(justify→ DOCXboth)marginTop/marginBottom: 映射到w:spacing的before/after(单位为 twips)lineHeight: 无单位 → 自动行距规则(比例);Npt→ 精确值;Npx→ 转换
单位转换。 编译器接受 px、pt、rem、em。rem 和 em 会基于 baseFontSize(默认 16)进行解析。其他单位(%、vh、ch 等)不被识别,相关属性会被跳过。
列表合并。 ul li 和 ol li 都映射到 DOCX ListParagraph 样式。如果两者都定义了,会合并它们的属性;逐属性而言,后面的条目胜出。
不支持的内容
这些是有意的限制
这些不是 bug。这些是功能的明确、文档化边界。如果你的工作流依赖下面任意一项,此功能就不是合适的工具。
- 跨源样式表。 浏览器安全机制会阻止访问任何来自不同源的样式表的
.cssRules。extractFromDocument会静默跳过这些样式表。如果你的主题托管在 CDN 上,请改为通过styles显式传入规则。 - 伪类、伪元素、媒体查询。
a:hover、p::first-line、@media (min-width: …):这些都不会映射到 DOCX,会被丢弃。 - CSS 变量和
calc()。 编译器读取的是声明值,而不是计算后的值,因此var(--brand)或calc(100% - 2rem)无法解析。请在传入样式之前先解析它们。 - 任意选择器。 这 16 个选择器就是全部支持范围。像
.prose p或article h1这样的后代选择器,只有在去除作用域前缀后能与映射精确匹配时才会生效;否则会被丢弃。 - 层叠与优先级。 编译器会把每个选择器压平成一组单一属性。如果同一个选择器在不同优先级下存在冲突规则,只有编译结果会进入 DOCX。层叠关系不会被保留。
- 计算后的样式继承。 浏览器提取器直接读取
document.styleSheets,不会遍历 DOM,也不会计算继承值。如果某个属性在浏览器中是继承得到的,但未在目标选择器上显式声明,它就不会被导出。
你可以预期什么
- 一个包含正确
styles.xml的 DOCX 文件,Word 用户可以在其中集中编辑样式。 - 每个匹配的选择器恰好对应一个 DOCX 样式条目,并且只包含成功映射的属性。其余内容要么被显式
styles覆盖合并,要么在导出时伴随console.warn被跳过。 - 确定性的行为:给定相同输入(
styles对象和 DOM 样式表),导出结果可以逐字节比较。 - 安全的服务端使用:如果
document未定义(Node、SSR),extractFromDocument不会产生任何作用。不会抛出错误,也不会注入任何内容。
你不应该预期什么
- 与导入侧完全往返一致。 某些 CSS → DOCX 的转换会丢失信息(例如:
line-height: 1.5→ 自动行距规则,但重新导入该 DOCX 时会把 line-height 重新输出为无单位倍数;如果 Word 对存储值做了标准化,它可能不会精确等于1.5)。 - 内联标记属性能够在往返后保留。 导出会接受每个选择器上的全部 12 个属性,包括
strong、em、u、s、a、code。导入时对应的 CSS 注入 会把这些内联标记选择器过滤到只保留它们的身份属性(例如strong只保留fontWeight,em只保留fontStyle,code只保留fontFamily/color/fontSize/backgroundColor)。为了避免通过优先级覆盖父级块样式,你设置的超出这些范围的内容在重新导入时都会被丢弃。要实现往返,例如strong上的颜色,请改为设置在父选择器(p、h1)上。 - 支持媒体查询感知的导出。 DOCX 不支持媒体查询。如果你的响应式 CSS 在移动端和桌面端不同,那么你得到的是调用
configure()时匹配到的规则(通常是桌面端)。 - 与浏览器渲染完全一致的视觉效果。 DOCX 的渲染引擎(Word、LibreOffice、Google Docs)对样式的解释与浏览器不同。请预期行距、字距和段落间距会有细微差异。
- 自动主题转换。 颜色、字体和字号都是 1:1 映射。Word 的“主题”(强调色、字体搭配)不是。如果你想使用 Word 主题,需要在导出选项中直接进行设置。
配置参考
ExportDocx.configure({
cssStyles: {
// 二选一:选择器 → CSS 声明的显式对象
styles?: {
p?: { fontSize?: string; color?: string; /* … */ },
h1?: { /* … */ },
// …任意一个 16 个选择器
},
// 或:从浏览器的实时样式表中提取
extractFromDocument?: boolean, // 默认:false
// 用于解析 rem / em 的基准大小
baseFontSize?: number, // 默认:16
},
})相关
- CSS injection (import):反向方向。
- Export styles:原始的 DOCX 导出样式指南(手动样式定义,不基于 CSS)。
- REST API:DOCX 导出端点。