How-to約 3 分鐘閱讀

用程式把 HTML 轉成 PDF:哪些 HTML 與 CSS 會被列印出來

實測 HTML 轉 PDF 能列印什麼:格線、彈性盒、@page 頁面尺寸、網頁字型與重複表頭都行,JavaScript 不會執行。附 curl 範例。

By the PDF123 team · Updated 2026-11-05

HTML 轉 PDF用 WeasyPrint 列印你的 HTML 與 CSS,用的不是瀏覽器。測試中,格線、彈性盒、@page 的尺寸與頁邊距、來自公開位址的網頁字型、重複的表頭與頁碼都排出來了;JavaScript 完全沒有執行。可以送一個 .html 檔案,也可以送一個 ZIP,裡面放 HTML 與它的樣式表、圖片、字型。頁面在一個公開位址上時,網址轉 PDF直接從位址完成同樣的事。

HTML 轉 PDF 到底會列印哪些 HTML 與 CSS?

呼叫就是一個 multipart 請求,檔案作為 fileInput:

curl -X POST https://pdf123.xyz/api/v1/convert/html/pdf \
  -F [email protected] \
  -o page.pdf

用命令列也一樣:

pdfx html-to-pdf page.html -o page.pdf

兩條指令我都在 2026-10-23 對本機執行的一份伺服器跑過,測試頁裡寫了 @page { size: A5; margin: 12mm }。curl 回傳 HTTP 200,pdfx 結束碼為 0,pdfinfo 回報 1 頁,419.528 x 595.276 點,也就是 A5。

下表來自一組很小的測試頁,每個都用同樣的方式轉換,再用 pdfinfo、pdftotext、pdffonts 與 pdfimages 檢查,排版問題則看轉譯出的圖片。表裡寫的是實際轉出來的結果,不是規格的承諾。

功能 我送出的內容 轉出來的結果
用 CSS 定頁面尺寸 @page { size: A5; margin: 12mm } 419.528 x 595.276 pt(A5)
自訂頁面尺寸 @page { size: 210mm 99mm } 595.276 x 280.63 pt
沒有 @page 規則 一個裸 HTML 檔案 595.276 x 841.89 pt(A4)
CSS 格線 grid-template-columns: 1fr 2fr 1fr; gap: 10mm,六個儲存格 三欄,寬度比 1:2:1,第 4 到 6 個儲存格在下一列
彈性盒 display: flex; justify-content: space-between,三個項目 項目從行的左邊緣分布到右邊緣
來自公開位址的網頁字型 @font-face 指向公開 CDN 上的 .woff 檔 以 @font-face 裡的名稱嵌入 PDF
打包在 ZIP 裡的字型 @font-face 用相對 url() 指向壓縮檔裡的檔案 嵌入 PDF
機器上安裝的字型 font-family: "Times New Roman" 在我的測試機上嵌入了;取決於伺服器有哪些字型
哪裡都沒有的字型 font-family: "NoSuchFontAnywhere", monospace 通用的 monospace 回退成機器上的某個字型
強制分頁 break-before: page 與 page-break-before: always 3 頁:第一次分頁前的內容,之後每次分頁一頁
表格跨多頁,表頭在 <thead> 裡 100 列的表格,A5 4 頁,每頁頂端都有表頭列
表格跨多頁,表頭是一般列 同一個表格,去掉 <thead> 4 頁,只有第 1 頁有表頭列
頁碼與頁首文字 @page { @bottom-center { content: "Page " counter(page) " of " counter(pages) } } Page 1 of 3、Page 2 of 3、Page 3 of 3,以及頁首文字
@media print 一個 print-only 區塊與一個 screen-only 區塊 列印區塊印出來了,螢幕區塊沒有
較新的 CSS 自訂屬性、calc()、linear-gradient、border-radius、transform: rotate() 全部畫出來了
filter 與 position: sticky filter: blur(3px) 與 position: sticky 模糊被忽略;黏性定位的區塊依一般區塊列印
JavaScript 一段設定 textContent 並呼叫 document.write 的指令碼 兩段文字都沒有出現;靜態文字出現了
<noscript> <noscript> 裡的文字 印出來了
公開位址上的圖片 <img src="https://..."> 嵌入了
私有位址上的圖片 位址是迴路位址的 <img> 沒有載入;印出替代文字;呼叫仍回傳 200

從程式產生 HTML 時,有兩列最要緊。只有表頭放在 <thead> 裡,每一頁才會重複表頭列。另外,指令碼寫進頁面的任何內容都到不了 PDF,在瀏覽器裡才建構內容的頁面,印出來的是它最初的空殼:單頁應用程式送來一個空的 <div id="root">,得到的就是一份空 PDF。

怎樣把 HTML 連同樣式表、圖片與字型一起送過去?

放進 ZIP。壓縮檔根目錄有 index.html 就用它,否則用第一個名稱以 .html 結尾的檔案;壓縮檔裡的 .htm 檔不會被選中。相對路徑從 HTML 檔案自己所在的資料夾算起。一個含 index.html、css/style.css、img/logo.png 與 fonts/roboto.woff 的 ZIP,這樣轉換:

curl -X POST https://pdf123.xyz/api/v1/convert/html/pdf \
  -F [email protected] \
  -o c.pdf

結果是一頁,樣式表生效,打包的字型以 @font-face 裡的名稱嵌入,300 x 120 的圖片也在。第二個 ZIP 根目錄沒有 index.html,只有 site/page.html 與 site/logo.png,轉換器用了 site/page.html,旁邊的圖片載入成功。完全沒有 .html 檔案的 ZIP 回傳 HTTP 400,reason 是 unsupported_file_type:The ZIP archive must contain an .html file. Markdown 轉 PDF 的做法不同,它的圖片路徑從壓縮檔根目錄算起,見不裝 Pandoc 與 LaTeX,把 Markdown 轉成 PDF。

你自己電腦上的檔案無法依路徑存取。頁面連結到的任何東西,要嘛在 ZIP 裡,要嘛在公開位址上。公開的 http 或 https 位址上的資源,會在轉譯時擷取。擷取器每次轉換最多允許 500 次擷取,每個資源最大 64 MiB,每個請求 15 秒。私有或內部網路的位址會被攔截,所以上面那張迴路位址上的圖片印出的是替代文字。轉譯預設在 180 秒後停止。

字型是不同機器之間結果會不同的地方。服務的 Docker 映像檔安裝了 DejaVu、Liberation、Noto 與 Noto CJK 字型套件。CSS 裡寫的字型名稱,伺服器上沒有就會換成回退字型,所以在你機器上看起來正常的 PDF,在伺服器上可能用了另一種字型。用 @font-face 載入字型,無論來自 ZIP 還是公開位址,都能避開這個問題。

背後是哪個轉譯器、哪個版本?

轉換器是 WeasyPrint,由 Python 執行,沒有無頭瀏覽器。服務的 Docker 映像檔安裝 weasyprint==70.0,路徑上是別的版本時建置會直接中止;我這台測試伺服器產出的 PDF,Producer 欄位裡是 WeasyPrint 70.0(pdfinfo 會印出它)。WeasyPrint 的文件說它不是以 WebKit 或 Gecko 這樣完整的轉譯引擎為基礎,它的 CSS 支援頁面寫著彈性盒模組「works for simple use cases but is not deeply tested」,格線模組「works for simple cases, but has some limitations」。複雜的版面在依賴它之前請先測試,上面的表只涵蓋了我試過的情形。

如果 HTML 只能透過一個位址取得呢?

網址轉 PDF接收 urlInput,自己擷取頁面,再用同一個引擎轉譯,所以同樣不會執行 JavaScript。在瀏覽器裡才建構內容的網站,印出來沒有那些內容。

curl -X POST https://pdf123.xyz/api/v1/convert/url/pdf \
  -F urlInput=https://example.com \
  -o output.pdf

它回傳 HTTP 200 與一份 1 頁 A4 的 PDF,Producer 欄位是 WeasyPrint 70.0;下載的檔名固定是 output.pdf。只接受公開的 http 與 https 位址:把迴路位址作為 urlInput,回傳 HTTP 400,reason 為 url_not_allowed,訊息是 Private, local and internal network addresses are not allowed. 頁面需要登入,或你要自己控制確切的位元組,就把 HTML 存下來,改用 HTML 轉 PDF。

常見問題

HTML 轉 PDF 會執行 JavaScript 嗎?

不會。測試裡,一段設定元素文字並呼叫 document.write 的指令碼,沒有往 PDF 裡加入任何內容。引擎只讀 HTML 與 CSS,所以請送出指令碼本來會產生的那份 HTML。

怎樣設定紙張大小與頁邊距?

在你自己的 CSS 裡寫 @page 規則,例如 @page { size: A5; margin: 12mm }。這個工具沒有紙張或頁邊距的選項,也不加入預設樣式表,沒有規則的頁面轉出來是 A4。

為什麼字型和我瀏覽器裡的不一樣?

CSS 裡的字型名稱是在伺服器上查找的,不是在你的電腦上,伺服器沒有的名稱會回退成別的字型。把字型打包進 ZIP,或用 @font-face 從公開位址載入,它就會嵌入 PDF。

能列印需要登入的頁面嗎?

網址轉 PDF 不行,它不會傳送 cookie。登入狀態下把 HTML 存下來,連同資源放進 ZIP,再用 HTML 轉 PDF。

Open tool
Process in the browser — no watermark, files removed after the job.
Open tool