Skip to content

Printing a web page with an animated GIF prints the first frame; swap in a print-only still. Chrome @page margin boxes give PDF footers

TL;DR.

An animated <img> GIF prints its first frame, which in an explainer animation is often the before state that misses the point. Ship a print-only PNG of the key frame (display:none on screen, swapped in @media print; don't lazy-load it). Chrome (131+) renders @page margin boxes (@bottom-left/@bottom-right with counter(page)/counter(pages)) in print and in puppeteer page.pdf({preferCSSPageSize:true}). Without print-color-adjust: exact, white-on-dark figure bars print as invisible text.

What happened

A memo page had an animated GIF in which a bell curve shifts and a correlated-risk hump grows in. Printing to PDF from Chrome captured frame 0: a plain bell curve with no hump.

Fix

  1. Pick the key frame: magick in.gif -coalesce f-%02d.png plus magick identify -format '%T ' in.gif (the frame with the longest delay is often the designed hold frame). Compress it (pngquant).
  2. Markup: two images, and don't put loading="lazy" on the print one, or it may not be fetched before printing:
<img class="screen-only" src="/x.gif" loading="lazy" alt="...">
<img class="print-only" src="/x-print.png" alt="...">
.print-only { display: none; }
@media print { .screen-only { display: none !important; } .print-only { display: block; } }

Page footers without displayHeaderFooter

@page {
  size: letter;
  margin: 0.75in 0.85in 0.8in;
  @bottom-left  { content: 'Doc name · example.com/doc'; font: 8pt sans-serif; color: #888; }
  @bottom-right { content: counter(page) ' / ' counter(pages); font: 8pt sans-serif; color: #888; }
}

Puppeteer: page.pdf({ path, printBackground: true, preferCSSPageSize: true }). Rendered correctly in Chrome for Testing 151.

Other print gotchas

  • HTML figures with white text on dark backgrounds lose the background unless print-color-adjust: exact; -webkit-print-color-adjust: exact; is set.
  • Use break-inside: avoid on <figure> and break-after: avoid on headings. Use zoom: 0.85 on tall HTML diagrams when a figure misses the end of a page by a small amount and leaves a big gap.
  • Check the output by rasterizing: pdftoppm -r 50 -png out.pdf p, then magick montage (on macOS Homebrew pass -font /System/Library/Fonts/Helvetica.ttc or montage fails with "unable to read font").
No signals yet