如何通过Web API/Chrome扩展API应用已存储的用户自定义字体?
如何应用存储的二进制字体文件到指定元素
可以通过Blob URL + 动态创建@font-face规则的方案实现,完全支持离线使用、无需重复下载,兼容自定义字体和Google Fonts下载后的二进制文件,核心依赖通用Web API,Chrome扩展环境下也能直接复用逻辑。
核心思路
将存储的二进制字体(base64/ArrayBuffer/Blob)转换为Blob对象,通过URL.createObjectURL()生成浏览器可识别的临时URL,再通过CSSOM动态注入@font-face规则,最后给目标元素指定对应的字体名称即可。
完整实现代码
根据你存储的字体格式,选择对应的处理逻辑:
1. 处理Base64格式(最常见存储形式)
// 获取存储的二进制字体(示例为base64格式,带/不带data前缀均可) const fontFile = await getSelectedFontAsync(); // 自定义唯一字体名称(可结合用户选择的字体名/ID生成,避免冲突) const fontName = "CustomEditorFont"; // 建议存储字体时同时记录MIME类型,比如font/ttf、font/woff2 const storedMimeType = "font/woff2"; // 步骤1:将Base64转换为Blob let blob; if (fontFile.startsWith('data:')) { // 处理带data前缀的base64 const [mimePart, dataPart] = fontFile.split(','); const mime = mimePart.split(':')[1].split(';')[0]; const byteChars = atob(dataPart); const byteArray = new Uint8Array(byteChars.length); for (let i = 0; i < byteChars.length; i++) { byteArray[i] = byteChars.charCodeAt(i); } blob = new Blob([byteArray], { type: mime }); } else { // 处理不带前缀的纯base64 const byteChars = atob(fontFile); const byteArray = new Uint8Array(byteChars.length); for (let i = 0; i < byteChars.length; i++) { byteArray[i] = byteChars.charCodeAt(i); } blob = new Blob([byteArray], { type: storedMimeType }); } // 步骤2:生成Blob URL const fontUrl = URL.createObjectURL(blob); // 步骤3:避免重复注入@font-face规则 const fontFormat = storedMimeType.split('/')[1]; const hasExistingRule = Array.from(document.styleSheets).some(sheet => { try { return Array.from(sheet.cssRules).some(rule => { return rule.type === CSSRule.FONT_FACE_RULE && rule.style.fontFamily === `"${fontName}"`; }); } catch (e) { // 跨域样式表会抛出权限错误,直接跳过 return false; } }); if (!hasExistingRule) { // 动态创建样式规则并插入页面 const styleEl = document.createElement('style'); styleEl.textContent = ` @font-face { font-family: "${fontName}"; src: url(${fontUrl}) format('${fontFormat}'); font-display: swap; } `; document.head.appendChild(styleEl); } // 步骤4:给目标元素应用字体 document.querySelector(".label").style.fontFamily = `"${fontName}"`;
2. 处理ArrayBuffer格式
const fontFile = await getSelectedFontAsync(); // ArrayBuffer类型 const fontName = "CustomEditorFont"; const storedMimeType = "font/ttf"; // 直接转换为Blob const blob = new Blob([fontFile], { type: storedMimeType }); const fontUrl = URL.createObjectURL(blob); // 后续注入@font-face、设置字体的逻辑和Base64示例完全一致
3. 处理Blob格式
const fontFile = await getSelectedFontAsync(); // Blob类型 const fontName = "CustomEditorFont"; const storedMimeType = fontFile.type; const fontUrl = URL.createObjectURL(fontFile); // 后续注入@font-face、设置字体的逻辑和Base64示例完全一致
关键注意事项
- 资源释放:当切换字体或关闭编辑器时,调用
URL.revokeObjectURL(fontUrl)释放Blob URL资源,避免内存泄漏。 - 字体名称唯一性:建议用用户选择的字体ID或文件名生成唯一名称,避免和系统字体、其他自定义字体冲突。
- MIME类型记录:存储字体时务必同时记录对应的MIME类型(如
font/woff2),确保@font-face的format属性正确,提升字体加载兼容性和性能。 - Chrome扩展适配:如果是Chrome扩展环境,仅需替换
getSelectedFontAsync为chrome.storage.local.get()等扩展API读取逻辑,核心的Blob转换、@font-face注入逻辑完全通用。
内容的提问来源于stack exchange,提问作者Luke Vo
相关产品推荐
相关产品推荐

