自定义字体服务 - 基于Node的Web字体解决方案

这篇具有很好参考价值的文章主要介绍了自定义字体服务 - 基于Node的Web字体解决方案。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  • 自定义字体服务 - 基于Node的Web字体解决方案
    • 背景
    • 技术选型
    • @font-face介绍
    • 实现方案(介绍字体设计、转换、兼容性处理等技术实现细节。)
    • 接口实现方式(实现中遇到的问题和解决方案)
    • 总结
    • 开源地址
    • 参考

背景

在前端开发中,字体是非常重要的组成部分,因为字体可以为页面提供良好的可读性和设计感。在设计中,经常需要使用一些特殊的字体,以突出设计效果或满足特殊的审美需求。但是,在使用一些奇怪字体的需求下,使用图片来替代字体可能会影响页面性能,特别是图片大小和加载时间的问题。

一般来说,为了解决这个问题,我们会使用CSS3中的@font-face提供的自定义字体功能。通过使用@font-face,我们可以自定义一个字体文件,将字体文件嵌入到网页中,从而避免使用图片来替代字体。这种方法可以解决一些特殊字体的问题,但是可能会面临一些挑战。英文字体文件通常比中文字体文件小得多。一个常见的英文字体文件大小通常不超过100KB,而一个中文字体文件可能会超过10MB。这是因为中文字体通常包含大量的字符,包括不同的汉字、符号和字体效果等。这种情况下,为了一两个字或者一行字,就需要加载几MB大小的整个字体文件,显然是不划算的。此外,在网络差的环境下,即使用户浏览完页面,字体文件也可能还没有加载完成,这时候已经没有意义了。
换个角度想想,虽然一个中文字体包含了几千个常用字,但一个网页去掉重复字的情况下,往往只包含数十个到数百个字。因此,是否有必要加载一个完整包含数千个字的字体文件,可以考虑只加载网页需要的字体,这样能够减小加载字体文件的大小,同时也能保证字体加载的速度。

技术选型

针对上面的两个问题,常见的解决方案有:

  1. font-spider :字蛛是一个智能 WebFont 压缩工具,它能自动分析出页面使用的 WebFont 并进行按需压缩。https://github.com/aui/font-spider

    * 优点:提供大量可商用字体,便捷获取。
    * 缺点:需要付费,版权复杂,可用性有限。
    
  2. font-carrier:font-carrier是一个功能强大的字体操作库,使用它你可以随心所欲地操作字体。https://github.com/purplebamboo/font-carrier

    * 优点:可以收集和备份已经购买的商用字体。
    * 缺点:需要确保拥有商用字体的正版授权。
    
  3. 有字库:有字库是全球第一中文web font(网络字体)服务平台,致力于美化网页界面,降低网页设计和维护的难度,同时提升效率。http://www.webfont.com/

    * 优点:提供大量可商用字体,便捷获取。
    * 缺点:需要付费,版权复杂,可用性有限。
    
  4. fontmin: fontmin是一个纯 JavaScript 字体子集化方案,提供了 APICLI的使用方式。是一个非常成熟实用的字体优化工具。http://ecomfe.github.io/fontmin/#feature

    * 优点:可以进行字体压缩和子集化优化。
    * 缺点:需要安装依赖,优化效果取决于字体本身。
    

@font-face介绍

@font-face 是 CSS 的一个规则,用于定义自定义字体。它允许网页设计者使用自定义字体,而不必依赖用户的计算机上已安装的字体。
使用 @font-face 规则,可以将字体文件(通常是 TrueType 字体文件或 OpenType 字体文件)嵌入到网页中,并通过 CSS 指定字体的名称和样式

以下是一个示例,演示如何使用 @font-face 定义并应用自定义字体:

@font-face {
  font-family: 'MyCustomFont';
  src: url('myfont.ttf');
}

body {
  font-family: 'MyCustomFont', sans-serif;
}

在上面的示例中,myfont.ttf 是字体文件的路径。通过 @font-face 规则定义了一个名为 ‘MyCustomFont’ 的自定义字体,然后在 body 元素中应用了这个字体。

实现方案(介绍字体设计、转换、兼容性处理等技术实现细节。)

综合考虑之后,我们采用的是fontmin。
自定义字体服务 - 基于Node的Web字体解决方案,前端

这是官网的一个例子,从一个大小为4.2M,包含7500+的字体包中,提取了7个字,输出的子集字体大小在4.5K左右。

结合我们的业务场景,为了方便管理,我们结合Node.js,开发了字体服务管理系统,实现了字体文件的上传和管理,目前支持TTF和OTF两种字体格式,可以根据字体文件和需要的文字,动态压缩并输出子集字体同时上传到cdn,同时提供了一键复制css的功能,复制完成后直接放在自己的css文件中,就可以直接使用。

使用步骤

第一步:在字体库管理列表维护所使用的字体文件,得到字体库名称以及将字体库同步传到cdn,获得url地址;
自定义字体服务 - 基于Node的Web字体解决方案,前端
第二步:在字体配置管理页面根据需要的字体和使用的文字得到压缩后的使用地址;
自定义字体服务 - 基于Node的Web字体解决方案,前端
第三步:拿到“复制地址”里的链接,通过@font-face设置自定义字体,就能实现我们想要的效果啦;

// 定义字体名称,src里就是复制的地址
@font-face {
  font-family: yezi; //自己起个字体名字
  src: url("https://xxx/yezi_5f27fae9ad916de19343e2b8a1635680.ttf");
}
// 使用
.font-test{
  font-size: 46px;
  font-family: yezi;  //设置成你上面自定义的字体
}

自定义字体服务 - 基于Node的Web字体解决方案,前端

接口实现方式(实现中遇到的问题和解决方案)

在维护的自己的字体文件时,能拿到字体包对应的key值,此key值是唯一的,在压缩字体的时候,基于接口设计了通用的解决方案,接口接收使用的字体包对应的key和需要压缩的文字,压缩的时候通过调用接口生成子集文件并同步上传到cdn,返回cdn地址。

  https://example.com/api/font?key=yezi&fontlibfile=url&word=word&pageNme=pageNmae
// key 表示使用的字体包对应的key
// fontlibfile 表示使用的字体包对应的url(我们的字体包是存在cdn上的)
// word 表示需要提取的文字
// pageNme 为了记录是哪个项目和页面使用(只针对我们的业务场景)

接口实现,因为我们的字体包存在cdn上,fontmin不支持远程文件做为源字体包,所以我们需要先将字体包下载下来临时存放在本地,压缩完成之后再删掉。

export default async (fontlibfile: string, key: string,  pageName: string, word: string) => {
  // fontlibfile 表示使用的字体包对应的url(我们的字体包是存在cdn上的)
  // key 表示使用的字体包对应的key
  // word 表示需要提取的文字
  // pageNme 为了记录是哪个项目和页面使用(只针对我们的业务场景)
    
  let data: any = {};
  let text = word;

  if (fontlibfile) data.fontlibfile = fontlibfile;
  if (text) data.word = text;
  if (pageName) data.pageName = pageName;
  if (key) data.key = key;

  data.fontUrl =`https://example.com/${text}.ttf`;

  if (!fontlibfile) throw new Error('字体库或key不存在');
  try {
    const cacheFile = path.join(__dirname, `./font/`);
    // 用于存放下载下来的源字体包
    if (!fs.existsSync(cacheFile)) {
      fs.mkdirSync(cacheFile, {recursive: true});
    } else {
      log.info("临时存放目录已存在");
    };
    const filePath = await tempDownload(fontlibfile);  // 获取下载之后的源字体文件地址
    const extname = path.extname(filePath);
    const useTtfType = (extname === '.ttf' || extname === '.TTF') ? true : false;  //因为支持ttf和otf两种格式,需要区分一下
    const fontmin = new Fontmin()
      .src(filePath)
      .use(useTtfType ? Fontmin.glyph({ text }) : Fontmin.otf2ttf({ text }))  //不管是ttf还是otf,最终我们都转成ttf格式

      const content:any = await new Promise((resolve, reject) => {
        fontmin.run((error, files) => {
          if (error) {
            return reject(error);
          }
          return resolve(files[0].contents);
        });
      });
    await writeFile(`${cacheFile}${text}.ttf`, content);
    const file = fs.readFileSync(`${cacheFile}${text}.ttf`);
    let res;
    res = await IMGCLIENT.client.put(`dm_auto_config_server/${text}.ttf`, file); // 将压缩后得到的子集字体文件上传到cdn
    fs.unlink(`${__dirname}/font/${text}.ttf`, (err) => {
      if(err) {
        log.info('删除文件失败');
      };
    });
    return res.url; // 拿到压缩后的子集字体文件地址
  } catch(error) {
    throw new Error('字体文件压缩失败');
  }
}

为了解决文字重复和避免重复压缩同样字体造成资源浪费,需要对文字进行去重,并考虑缓存。

    // 对文字去重以及排序
    let text = Array.from(new Set(word))
    .sort()
    .join('');

    const textMd5 = `${key}_${md5(text)}`;  // 并将上面的代码中的text替换成textMd5
    const exist = await GetFontManagByBufferName(`${textMd5}`); // 去数据库中差是否有缓存
    if (exist !== null) {
      throw new Error(`字体配置中已经存在了字体库为${fontlibName}key值为${key}的字体配置`);  // 直接去复制已有的文件就好了
    }
    

如果对已经压缩好的文字进行编辑,但是已经有很多页面使用了,那编辑的时候还要避免子集文件地址的变更。不然一旦重新编辑,地址就会发生改变,那已经使用的页面还需要更换对应的地址并重新发布,非常不友好。

// 编辑时入参增加 id:新建时生成的唯一值,bufferName:新建时生成的由key和textMd5组合而成

const textMd5 = id ? bufferName : `${key}_${md5(text)}`;

解决了地址不能变更的事情,新的问题又来了,那就是cdn缓存,因为我们的文件是自动上传到cdn的,地址不变,如果不强制清缓存,请求不到新的资源。

// 我们的资源是放在阿里云上的,查了api,发现api里有上传时强制不缓存的设置

res = await IMGCLIENT.client.put(`dm_auto_config_server/${textMd5}.ttf`, file, { headers: {'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate', 'Pragma': 'no-cache', 'Expires': -1} });

到这里,自定义字体服务的核心功能就完成了。来看下效果吧
自定义字体服务 - 基于Node的Web字体解决方案,前端
原来的叶子字体包大小是4.5M,压缩之后提取了我们需要的文字,大小为4.1k。

总结

在这个自定义字体服务的例子中,我们实现了对字体的优化和管理。通过合理的设计和优化,我们可以减小字体文件的大小,提高网页的加载速度和用户体验。但是,这只是优化字体的一个方面。为了确保字体的质量和用户体验,我们还需要注意字体的可读性、风格、版权等问题。同时,在开发过程中,我们也需要考虑字体的兼容性和响应式设计等方面,以适应不同设备和不同屏幕尺寸的用户。
fontmin 虽然很厉害,但不是万能的,由于 font 文件表之间极其复杂的相互关联,转换得到的子字体将会破坏一部分关联信息(比如会影响字体竖排时的间距)。在压缩数字的时候,如果不加入一个标点符号,会导致压缩失败,等等。希望对大家有所帮助,如果有疑问可以多多交流与反馈,共同改进这个方案。

参考

  1. FontFace https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face
  2. fontmin http://ecomfe.github.io/fontmin/#feature
  3. 基于 Node.js 的 WebFont 解决方案

作者:洞窝-小米文章来源地址https://www.toymoban.com/news/detail-606536.html

到了这里,关于自定义字体服务 - 基于Node的Web字体解决方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python利用Matplotlib绘图无法显示中文字体的解决方案

    问题描述 在Python利用Matplotlib绘图的时候,无法显示坐标轴上面的中文和标题里面的中文 运行显示: 解决方法一: 解决方法二: 两种方法都可以使中文正常显示 补充: SimSun :宋体;KaiTI:楷体;Microsoft YaHei:微软雅黑 LiSu:隶书;FangSong:仿宋;Apple LiGothic Medium:苹果丽中黑

    2024年01月23日
    浏览(54)
  • 容器编排的未来:探索基于Kubernetes的微服务编排解决方案

    作者:禅与计算机程序设计艺术 当今的云计算环境下,容器技术正在成为主流,越来越多的公司选择基于容器技术实现应用部署及运行。容器编排技术也逐渐被普遍采用。通过容器编排工具可以将复杂的分布式系统架构部署、管理及扩展起来,从而提供一个高可用、易于维护

    2024年02月14日
    浏览(40)
  • 【小程序】使用font-awesome字体图标的解决方案(图文)

    (1)、在项目根目录下建立一个文件夹,命名随意,我的文件夹名称是js。 (2)、再新建一个文件font-awesome.wxss (3)、把下载解压后的font-awesome中的css文件中的font-awesome.css内容复制到font-awesome.wxss中 注意:从 红框往下(从.fa{) 的内容开始复制,红框内的内容不复制   

    2024年02月07日
    浏览(52)
  • 基于WebRTC技术的EasyRTC视频云服务系统在线视频客服解决方案

    随着互联网技术的发展,视频客服也成为服务行业的标配体验,基于WebRTC实时通信技术,客服人员与用户可以建立实时双向的视频交互与沟通。借助视频客服功能可以更加直观地了解用户的需求,提高沟通效率,并帮助用户解决问题。视频客服作为移动互联时代+客服的最佳实

    2024年01月25日
    浏览(43)
  • 在CSDN学Golang场景化解决方案(基于grpc的微服务开发脚手架)

    在Golang基于gRPC的微服务开发中,可以采用TLS加密通信来确保服务与服务之间的安全通信。下面是一个简单的设计示例: 生成证书和密钥: 定义gRPC服务器: 客户端连接gRPC服务器: 在服务实现中添加TLS加密通信: 这样,在Golang基于gRPC的微服务开发中,就可以使用TLS加密通信

    2024年02月14日
    浏览(50)
  • 基于Linux服务器出现“No space left on device”错误的解决简单有效方案

    翻译为 返回根目录 查看根目录root下各文件夹的大小情况, 注意:运行下面命令后需要输入用户密码,然后耐心等待存储计算及显示。 进入根目录root下的home文件夹 继续查看home文件夹下各文件夹的大小情况, 注意:运行下面命令后需要输入用户密码,然后耐心等待存储计算

    2024年02月02日
    浏览(40)
  • 为银行“面对面”服务安全护航|基于银河麒麟操作系统的金融柜面解决方案_银河麒麟桌面系统串口号

    • 银河麒麟操作系统经过了严格的质量控制和测试,具有高效稳定的运行环境,能够保证金融柜面业务的顺畅运行。 • 推进柜面相关业务基于国产化系统的改造,柜面设备向国产化迈进。 已应用于多家银行,多个应用场景 升腾终端搭配银河麒麟桌面操作系统V10,基于国产

    2024年04月16日
    浏览(46)
  • uniapp引入第三方字体库如(宋体、喜鹊燕书体、字小魂歌以晓手迹行楷体等) 最优解决方案

    最近在开发一个写对联的小程序,其中要求 对联文字以不同字体呈现,比如(宋体、喜鹊燕书体、字小魂歌以晓手迹行楷体等) ,如图: 一般UI设计给的都是这种.tff格式的字体文件,如图: 那么怎么在uniapp中加载第三方字体库呢? 经过几天的研究,找到了最优的一个解决

    2024年02月03日
    浏览(44)
  • 安装了node.js,但是npm命令不可用的解决方案

    今天想创建一个vue项目,发现npm命令用不了了 第一步:检查是否安装了node.js 第二步:检查node.js的安装路径是否添加到了Path环境变量 右键单击【此电脑】,在显示的菜单里点击【属性】,此时会打开系统设置窗口,点击如下位置的【高级系统设置】,在弹出的系统属性小窗

    2024年02月11日
    浏览(74)
  • Node.js16.15.1的一个报错及解决方案

    最近在进行Node.js的下载安装和环境的配置,在官网上下载了LTS版本16.15.1,没想到在后续的使用中出现一种报错。 例如,在命令提示符窗口中输入 npm -v 想要查看npm的版本号: 关于这个报错,我一开始的解决方案是将Node.js安装目录下的 npm.cmd 文件第12行的 prefix -g 改成 prefix

    2023年04月08日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包