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

Puppeteer生成PDF时自定义字体不加载(截图正常)、div背景色异常求助

核心问题排查与解决步骤

一、自定义字体生成PDF时失效(回退Times New Roman)

你之前的等待逻辑存在两个核心问题,直接导致字体加载校验失效:

  • 硬加15秒延时没有针对性,全新无缓存的Puppeteer上下文如果遇到字体路径404、CORS拦截,哪怕等1分钟也会回退默认字体;
  • 你写的page.evaluateHandle('document.fonts.ready')没有实际等待Promise完成,只是拿到了Promise对象的句柄就直接执行PDF生成,根本没等字体就绪,这也是为什么你在evaluate里取document.fonts经常返回undefined——旧版本Chromium在headless打印模式下不会完整暴露FontFace API接口。

对应修正操作:

  • 替换原有等待逻辑,不依赖页面内的FontFace API,直接监听字体资源的网络请求完成,再加字体可用性校验:
    // 替换原有的15秒硬延时、无效的fonts.ready调用
    // 等待所有woff字体文件的网络请求返回完成
    await page.waitForRequest(/\.woff2?$/, { timeout: 30000 });
    // 主动校验自定义字体是否真正加载完成,避免路径错误导致的静默回退
    await page.evaluate(() => {
      const testFontSize = '12px';
      const customFont = `${testFontSize} ProximaNova-Regular, sans-serif`;
      const fallbackFont = `${testFontSize} sans-serif`;
      const canvas = document.createElement('canvas').getContext('2d');
      // 测量自定义字体的文本渲染宽度
      canvas.font = customFont;
      const customWidth = canvas.measureText('字体渲染宽度校验样本').width;
      // 测量回退字体的文本渲染宽度
      canvas.font = fallbackFont;
      const fallbackWidth = canvas.measureText('字体渲染宽度校验样本').width;
      // 宽度差小于2px说明自定义字体未生效,强制重排触发加载
      if (Math.abs(customWidth - fallbackWidth) < 2) {
        document.documentElement.style.fontFamily = '"ProximaNova-Regular", sans-serif';
      }
    });
    
  • 调整Puppeteer启动参数,避免字体加载被浏览器安全策略拦截:
    const browser = await puppeteer.launch({
      headless: true,
      args: [
        '--disable-web-security', // 避免styled-components生成的@font-face被CORS规则拦截
        '--font-render-hinting=none' // 关闭Chromium字体渲染提示,避免字重匹配错误导致的字体回退
      ]
    });
    
  • 额外校验:确认你写在@font-face里的字体路径/fonts/ProximaNova-Regular.woff是真的部署在站点根路径下的,浏览器截图显示正常很大概率是本地缓存了旧的资源,Puppeteer是完全无缓存的全新上下文,一旦字体路径返回404,就会直接静默回退系统默认字体。

二、PDF中出现截图不存在的多余背景色

这个问题基本都是Chromium打印PDF时的渲染特性导致的,不是页面样式本身的问题:

  • Puppeteer调用page.pdf时,默认printBackground参数为false,打印时会自动忽略页面自定义的背景色,同时对带透明效果的元素(比如用了backdrop-filter、透明色的div)自动叠加不透明的白色背景,就会出现截图里完全不存在的色块。
  • 对应修正操作:
    调整page.pdf的调用参数,显式开启背景打印,关闭不必要的打印优化:
    await page.pdf({
      path: 'hn.pdf',
      format: 'a4',
      printBackground: true, // 必须显式开启,否则Chromium会自动给透明元素叠加默认白背景
      preferCSSPageSize: true,
      displayHeaderFooter: false, // 关闭默认的页眉页脚,避免额外的色块干扰
      margin: { top: 0, right: 0, bottom: 0, left: 0 }
    });
    
  • 如果调整参数后还是有多余背景,就检查页面内所有用了backdrop-filter的元素——Chromium打印模式下完全不支持毛玻璃效果渲染,会强制给这类元素加不透明背景,可以在生成PDF前临时把这类样式清掉:
    await page.evaluate(() => {
      // 打印前临时移除毛玻璃样式,避免自动叠加背景
      document.querySelectorAll('*').forEach(el => {
        el.style.backdropFilter = 'none';
        el.style.webkitBackdropFilter = 'none';
      })
    })
    

内容的提问来源于stack exchange,提问作者Dharmi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 11:15:03