You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 04:40:34