puppeteer: Inconsistent text rendering in headless mode

EDIT: The fix is to add --font-render-hinting=none to the launch args. E.g.

  var browser = await puppeteer.launch({
    headless: true,
    args: ['--font-render-hinting=none']
  });

Original Comment: Font spacing seems to be inconsistent between headless and non headless mode. This is likely a Chromium bug for Puppeteer versions 1.2.0 and above.

Steps to reproduce

Tell us about your environment:

  • Puppeteer version: 1.2
  • Platform / OS version: Linux
  • URLs (if applicable):
  • Node.js version: 8.6.0

What steps will reproduce the problem?

  1. screenshot.js
'use strict';

const puppeteer = require('puppeteer');

(async() => {
  const browser = await puppeteer.launch({ headless: true }); // toggle to false
  const page = await browser.newPage();
  await page.goto('file:///tmp/test.html');
  await page.waitFor(5000);
  await page.screenshot({path: '/tmp/screenshot.png'});
  await browser.close();
})();
  1. test.html
<html>
  <head>
    <link rel="stylesheet"
          href="https://fonts.googleapis.com/css?family=Lato">
    <style>
      body {
        font-family: 'Lato', serif;
        font-size: 15px;
      }
      div.a {
        line-height: 0.5;
      }
    </style>
  </head>
  <body>
    <div class="a">
      <div>aaaaa..............................................................................|111</div><br>
      <div>qwertyasdfzxcvyuiohjklbnm................................|222</div><br>
      <div>longlonglonglonglonglonglonglongshorty......|333</div>
    </div>
  </body>
</html>
  1. node /tmp/screenshot.js, then repeat with headless: false

What is the expected result? Text is correctly aligned and looks the same as opening the HTML in browser. headless: false

headless_false

What happens instead? Text is misaligned with headless: true

headless_true

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 55
  • Comments: 30 (5 by maintainers)

Commits related to this issue

Most upvoted comments

--font-render-hinting=none seems to be the trick for me

After digging a little bit more, I found that the inconsistency is caused by https://github.com/GoogleChrome/puppeteer/pull/2072

which in turn, is from https://github.com/chromium/chromium/commit/e1b855d4545dc4fff19cee500d7ce105126f3bd2

If I understand correctly the changes to Chromium, Puppeteer’s Launcher.js should set DEFAULT_ARGS for --font-render-hinting to medium instead of leaving it at default. Doing so does indeed resolve this issue.

I can make a PR if this is an acceptable solution. Any thoughts, @aslushnikov?

It’s '--font-render-hinting=medium'. Mind the =

I found quick hot-fix on CSS-level. I fixed my broken SVG with:

<style>
  * {
    text-rendering: geometricprecision !important;
  }
</style>

This approach works for me with Google fonts. Had the issue with “Source Sans Pro”, the font looked really weird.
Now it’s fixed! Thanks!

I found quick hot-fix on CSS-level. I fixed my broken SVG with:

<style>
  * {
    text-rendering: geometricprecision !important;
  }
</style>

You can see the text overlapping here image

Also the extra spacing image

Hi All! I have been encountered with the same problem of unnecessary space and also the text overlapping:

Versions: “puppeteer”: “14.1.1”

Code: args: [ ‘–no-sandbox’, ‘–headless’, ‘–enable-logging’, ‘–window-size=820,480’, ‘–hide-scrollbars’, ‘–printBackground=true’, ‘–disable-dev-shm-usage’, ‘–font-render-hinting=medium’ ]

I had the same problem, my text position was one pixel off on m1 macs vs intel macs. In the end, a combination of the following flags helped: `--window-size=${resolution.w},${resolution.h}`, "--font-render-hinting=none", "--force-color-profile=generic-rgb", "--disable-gpu", "--disable-translate", "--disable-extensions", "--disable-accelerated-2d-canvas", "--deterministic-mode", "--disable-skia-runtime-opts", "--force-device-scale-factor=1", "--js-flags=--random-seed=1157259157", "--disable-partial-raster", "--use-gl=swiftshader" posted here, so it saves some time for the next person. I spent more than one day on this.

I noticed this issue was not fully fixed using the suggested flag. I found that on wikipedia pages, some times another word would fit into a line on my local browser while on the devtools browser (through the debugging port), I saw that the word is actually located after a newline character. I noticed it on the following wikipedia page (that happened to be the featured article of the day when I first encountered the issue): https://en.wikipedia.org/wiki/Tecumseh

EDIT: I noticed that the flag --disable-font-subpixel-positioning improved the results more than the --font-render-hinting=none I was using before, but still I’ve noticed some line breaks that only occurred on the browser while running on a container.

EDIT 2: After checking a bit deeper, I found out that apparently wikipedia is 15 pixels wider on OSx than it is on a linux VM, This is what caused the issue after disabling the subpixel positioning (which is still crucial for it to work).

FWIW I had to combine --font-render-hinting=none and CSS * { -webkit-font-smoothing: antialiased; } in order to get consistent results between Ubuntu and MacOS.

I was having issues with text on a PDF rendered by Puppeteer running within a Docker container. The issue was only visible on low-res displays, at low zoom levels (i.e. whole page view) and only when opened in Adobe Reader. Other viewers, including OSX preview, Slack, web browsers etc were all fine.

I tried all of the suggestions listed here to no avail. In the end, using this Docker image instead of the default Node image is the only change that produced any noticeable difference for me. Hopefully this can be of use to someone else!

reelevant/docker-node-infinality Based on node. Add misc font families and infinality for font rendering.

I have the same issue using the puppeteer latest version on CentOS and I have the same problem. I have tried the --font-render-hinting=none argument on puppeteer.launch() but with no luck. I noticed that for some reason the rendering adds 1px letter-spacing. The same implementation on macOS is working just fine.