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

如何从字体链接中动态提取字体元数据(名称、字重、样式)

如何从字体链接中动态提取字体元数据(名称、字重、样式)

项目背景与需求

我正在做一个支持自定义字体并应用到文本的项目,项目里已经有默认字体和自定义字体了。现在想新增一个功能,让用户通过链接添加自己的字体,流程是这样的:

  • 用户输入/插入字体链接,格式比如 https://link.com/fonts/Arial/arial-bold.ttf
  • 程序获取链接后,从字体中提取元数据:名称、font-weight、font-style

现有代码定义

字体相关类型

type TFontType = 'recent' | 'default' | 'custom';

type TFontStyle = {
   weight: number | string;
   style: string;
   link?: Nullable<string>;
};

type TFont = {
   id?: string;
   family: string;
   link?: Nullable<string>;
   styles: TFontStyle[];
   type?: TFontType;
};

type TFontController = {
   selected: Nullable<TFont>;
   fonts: TFont[];
};

我尝试过的函数

(原内容中代码未完整展示,此处略)


我给你整理的可行解决方案

要从远程字体链接里提取这些元数据,前端这边有几种靠谱的实现方式,我给你拆解一下:

1. 用浏览器自带的Font Face API解析(最准确)

浏览器的FontFace接口是专门处理字体加载和解析的,能直接拿到字体文件里的真实元数据,这是最靠谱的方式:

async function extractFontMetadata(fontUrl) {
  try {
    // 临时创建一个FontFace实例
    const tempFont = new FontFace('temp-placeholder', `url(${fontUrl})`);
    // 等待字体加载完成
    await tempFont.load();
    // 可以把临时字体加到文档里(如果不需要长期用,之后也能移除)
    document.fonts.add(tempFont);
    
    // 从加载好的字体里拿元数据
    return {
      name: tempFont.fullName || tempFont.family,
      weight: tempFont.weight,
      style: tempFont.style
    };
  } catch (err) {
    console.error('加载字体出错啦:', err);
    return null;
  }
}

⚠️ 注意:这种方式受CORS限制哦,如果字体所在的服务器没配置允许你的域名跨域访问,就会加载失败,得确保字体链接支持CORS。

2. 解析文件名当降级方案

如果遇到CORS问题没法用API,那只能退而求其次,从文件名里猜元数据了——前提是文件名比较规范,比如你举的arial-bold.ttf这种:

function guessMetadataFromFilename(fontUrl) {
  // 从链接里抠出最后一段的文件名
  const filename = fontUrl.split('/').pop();
  if (!filename) return null;
  
  // 去掉后缀(比如.ttf/.woff2)
  const nameWithoutExt = filename.replace(/\.[^/.]+$/, '');
  // 按横杠分割名称和样式部分
  const [family, ...styleParts] = nameWithoutExt.split('-');
  
  let weight = '400'; // 默认正常字重
  let style = 'normal'; // 默认正常样式
  
  if (styleParts.length > 0) {
    const styleStr = styleParts.join('-').toLowerCase();
    // 匹配常见的字体关键词
    const styleMap = {
      bold: '700',
      light: '300',
      medium: '500',
      regular: '400',
      italic: 'italic',
      'bold-italic': { weight: '700', style: 'italic' }
    };
    
    const matched = styleMap[styleStr];
    if (typeof matched === 'string') {
      if (matched === 'italic') {
        style = matched;
      } else {
        weight = matched;
      }
    } else if (matched) {
      weight = matched.weight;
      style = matched.style;
    }
  }
  
  return {
    name: family.charAt(0).toUpperCase() + family.slice(1),
    weight,
    style
  };
}

这种方式的准确性全靠文件名的规范性,适合当API方案的兜底。

3. 两种方案结合用

平时可以把两种方式结合起来,优先用API拿准确数据,失败了再用文件名猜:

async function getFontMetadata(fontUrl) {
  const apiData = await extractFontMetadata(fontUrl);
  if (apiData) return apiData;
  // 加载失败,用降级方案
  return guessMetadataFromFilename(fontUrl);
}

备注:内容来源于stack exchange,提问作者Lvasche

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 13:25:32