如何从字体链接中动态提取字体元数据(名称、字重、样式)
如何从字体链接中动态提取字体元数据(名称、字重、样式)
项目背景与需求
我正在做一个支持自定义字体并应用到文本的项目,项目里已经有默认字体和自定义字体了。现在想新增一个功能,让用户通过链接添加自己的字体,流程是这样的:
- 用户输入/插入字体链接,格式比如
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
相关产品推荐
相关产品推荐

