HTML轉PDF:如何在 C# 中將 HTML 元素轉換為 PDF

This article was translated from English: Does it need improvement?
Translated
View the article in English

IronPDF 並未提供內建的 SelectElementSelectCss 方法來鎖定特定的 HTML 元素。 ChromePdfRenderer 可渲染完整的 HTML 文件 —— 完整頁面、完整 URL 或完整 HTML 字串。 若要從頁面的特定區段產生 PDF,我們會在渲染前透過以下四種方法之一將目標元素隔離:JavaScript DOM 操作、CSS 注入、伺服器端 HTML 片段提取,或透過 JS 定位進行 URL 渲染。

每種方法都適用於不同的限制條件。 JavaScript DOM 隔離機制在渲染 URL 或完整網頁時發揮作用,此時我們需要移除目標內容以外的所有元素。 CSS 注入可在不修改 DOM 的情況下隱藏不需要的內容。 當我們能夠存取原始 HTML 時,伺服器端擷取能提供最乾淨的結果。 透過 JS 定位進行的 URL 渲染,可處理來源 HTML 不可用的即時儀表板及第三方頁面。

立即開始 30天試用,體驗這四種解決方案。

快速入門:HTML轉PDF — 將特定 HTML 元素擷取為 PDF

透過 JavaScript DOM 隔離機制與 WaitFor 選取 CSS 選擇器中的任意元素,並僅將該片段渲染至 PDF。

  1. 使用NuGet套件管理器安裝https://www.nuget.org/packages/IronPdf

    PM > Install-Package IronPdf
  2. 複製並運行這段程式碼。

    using IronPdf;
    
    var renderer = new ChromePdfRenderer();
    renderer.RenderingOptions.EnableJavaScript = true;
    renderer.RenderingOptions.JavaScript = @"
        var target = document.querySelector('#invoice-summary');
        document.body.innerHTML = target.outerHTML;
    ";
    renderer.RenderingOptions.WaitFor.HtmlQuerySelector("#invoice-summary", 10000);
    
    var pdf = renderer.RenderHtmlAsPdf(fullPageHtml);
    pdf.SaveAs("invoice-summary.pdf");
  3. 部署到您的生產環境進行測試

    今天就在您的專案中開始使用免費試用IronPDF

    arrow pointer

簡化工作流程(3 個步驟)

  1. 透過 NuGet 安裝 IronPDF:Install-Package IronPdf
  2. 設定 ChromePdfRenderOptions.JavaScript 以隔離目標元素,並設定 WaitFor 以確保其存在
  3. 呼叫 RenderHtmlAsPdf()RenderUrlAsPdf() — 該 PDF 僅包含獨立的內容

如何透過 JavaScript DOM 操作來隔離元素?

ChromePdfRenderOptions.JavaScript 屬性接受一段 JavaScript 字串,該程式碼會在 HTML 載入後、PDF 渲染前執行。 透過將 document.body.innerHTML 替換為目標元素的 outerHTML,我們便能從渲染後的頁面中移除所有其他內容。 這是最通用的做法——它同時適用於 RenderHtmlAsPdf()RenderUrlAsPdf()

WaitFor.HtmlQuerySelector() 方法可確保在 JavaScript 執行前,目標元素已存在於 DOM 中。 這對於包含非同步內容的頁面至關重要——例如 React 元件、Angular 模板,或是於初始頁面載入後才載入的 API 驅動資料。

using IronPdf;

string fullPageHtml = @"
<html>
<body>
    <header><h1>Acme Corp Invoice</h1></header>
    <nav>Navigation links...</nav>
    <div id='invoice-summary'>
        <h2>Invoice #12345</h2>
        <table>
            <tr><td>Widget A</td><td>$49.99</td></tr>
            <tr><td>Widget B</td><td>$29.99</td></tr>
            <tr><td><strong>Total</strong></td><td><strong>$79.98</strong></td></tr>
        </table>
    </div>
    <footer>Footer content...</footer>
</body>
</html>";

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;

// Replace the body with only the target element
renderer.RenderingOptions.JavaScript = @"
    var el = document.querySelector('#invoice-summary');
    if (el) {
        document.body.innerHTML = el.outerHTML;
    }
";

// Wait for the target element to exist before JS executes
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("#invoice-summary", 10000);

PdfDocument pdf = renderer.RenderHtmlAsPdf(fullPageHtml);
pdf.SaveAs("invoice-summary-only.pdf");
using IronPdf;

string fullPageHtml = @"
<html>
<body>
    <header><h1>Acme Corp Invoice</h1></header>
    <nav>Navigation links...</nav>
    <div id='invoice-summary'>
        <h2>Invoice #12345</h2>
        <table>
            <tr><td>Widget A</td><td>$49.99</td></tr>
            <tr><td>Widget B</td><td>$29.99</td></tr>
            <tr><td><strong>Total</strong></td><td><strong>$79.98</strong></td></tr>
        </table>
    </div>
    <footer>Footer content...</footer>
</body>
</html>";

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;

// Replace the body with only the target element
renderer.RenderingOptions.JavaScript = @"
    var el = document.querySelector('#invoice-summary');
    if (el) {
        document.body.innerHTML = el.outerHTML;
    }
";

// Wait for the target element to exist before JS executes
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("#invoice-summary", 10000);

PdfDocument pdf = renderer.RenderHtmlAsPdf(fullPageHtml);
pdf.SaveAs("invoice-summary-only.pdf");
Imports IronPdf

Dim fullPageHtml As String = "
<html>
<body>
    <header><h1>Acme Corp Invoice</h1></header>
    <nav>Navigation links...</nav>
    <div id='invoice-summary'>
        <h2>Invoice #12345</h2>
        <table>
            <tr><td>Widget A</td><td>$49.99</td></tr>
            <tr><td>Widget B</td><td>$29.99</td></tr>
            <tr><td><strong>Total</strong></td><td><strong>$79.98</strong></td></tr>
        </table>
    </div>
    <footer>Footer content...</footer>
</body>
</html>"

Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.EnableJavaScript = True

' Replace the body with only the target element
renderer.RenderingOptions.JavaScript = "
    var el = document.querySelector('#invoice-summary');
    if (el) {
        document.body.innerHTML = el.outerHTML;
    }
"

' Wait for the target element to exist before JS executes
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("#invoice-summary", 10000)

Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(fullPageHtml)
pdf.SaveAs("invoice-summary-only.pdf")
$vbLabelText   $csharpLabel

該 JavaScript 程式碼會將整個主體內容替換為 #invoice-summary div 中的 outerHTML。 生成的 PDF 僅包含發票表格——無頁首、無導覽列、無頁尾。 當以 ID 為目標時WaitFor.HtmlElementById() 方法提供了一種更簡便的替代方案:

// Alternative: wait by ID directly
renderer.RenderingOptions.WaitFor.HtmlElementById("invoice-summary", 10000);
// Alternative: wait by ID directly
renderer.RenderingOptions.WaitFor.HtmlElementById("invoice-summary", 10000);
' Alternative: wait by ID directly
renderer.RenderingOptions.WaitFor.HtmlElementById("invoice-summary", 10000)
$vbLabelText   $csharpLabel

對於複雜的選擇器(類別名稱、資料屬性、嵌套元素),HtmlQuerySelector() 接受任何 document.querySelector() 所能接受的有效 CSS 選擇器字串。 其他 WaitFor 便利方法包括 HtmlElementByName() 以及 HtmlElementByTagName() —— 這些方法在內部皆會委派給 HtmlQuerySelector(),但能讓程式碼的意圖更為清晰。

當目標元素依賴於父容器繼承的樣式時,outerHTML 的替換可能會遺漏依賴於祖先選擇器的 CSS 規則(例如:.dashboard .widget table { ... }). 為確保上述要求,請將 <head> 中的相關 <style><link> 標籤複製到 JS 隔離區中:

renderer.RenderingOptions.JavaScript = @"
    var el = document.querySelector('#invoice-summary');
    if (el) {
        var head = document.head.innerHTML;
        document.body.innerHTML = el.outerHTML;
        document.head.innerHTML = head;
    }
";
renderer.RenderingOptions.JavaScript = @"
    var el = document.querySelector('#invoice-summary');
    if (el) {
        var head = document.head.innerHTML;
        document.body.innerHTML = el.outerHTML;
        document.head.innerHTML = head;
    }
";
renderer.RenderingOptions.JavaScript = "
    var el = document.querySelector('#invoice-summary');
    if (el) {
        var head = document.head.innerHTML;
        document.body.innerHTML = el.outerHTML;
        document.head.innerHTML = head;
    }
"
$vbLabelText   $csharpLabel

此版本保留原始 <head> 內容(樣式表、字型、元標籤),僅替換正文部分。 《JavaScript 轉 PDF 操作指南》與《WaitFor 操作指南》涵蓋了額外的配置選項,包括針對具有多個非同步資料來源的頁面所使用的 NetworkIdle0()

如何透過 CSS 注入隔離元素?

ChromePdfRenderOptions.CustomCssUrl 屬性接受樣式表的檔案路徑或 URL,IronPDF 會在渲染前套用該樣式表。 我們不直接操作 DOM,而是透過 CSS display: none 將目標元素以外的所有內容隱藏起來。 此方法可保留原始的 DOM 結構,並完全避免執行 JavaScript。

using IronPdf;

// Create a CSS file that hides everything except #invoice-summary
string cssContent = @"
body > *:not(#invoice-summary) {
    display: none !important;
}
#invoice-summary {
    display: block !important;
    margin: 0;
    padding: 20px;
}
";
File.WriteAllText("isolate-element.css", cssContent);

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CustomCssUrl = "isolate-element.css";

PdfDocument pdf = renderer.RenderHtmlAsPdf(fullPageHtml);
pdf.SaveAs("invoice-css-isolated.pdf");
using IronPdf;

// Create a CSS file that hides everything except #invoice-summary
string cssContent = @"
body > *:not(#invoice-summary) {
    display: none !important;
}
#invoice-summary {
    display: block !important;
    margin: 0;
    padding: 20px;
}
";
File.WriteAllText("isolate-element.css", cssContent);

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CustomCssUrl = "isolate-element.css";

PdfDocument pdf = renderer.RenderHtmlAsPdf(fullPageHtml);
pdf.SaveAs("invoice-css-isolated.pdf");
Imports IronPdf
Imports System.IO

' Create a CSS file that hides everything except #invoice-summary
Dim cssContent As String = "
body > *:not(#invoice-summary) {
    display: none !important;
}
#invoice-summary {
    display: block !important;
    margin: 0;
    padding: 20px;
}
"
File.WriteAllText("isolate-element.css", cssContent)

Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.CustomCssUrl = "isolate-element.css"

Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(fullPageHtml)
pdf.SaveAs("invoice-css-isolated.pdf")
$vbLabelText   $csharpLabel

注意:CustomCssUrl 屬性僅在從 HTML 字串渲染時與 RenderHtmlAsPdf() 配合使用。 關於 URL 渲染,請將 CSS 注入代碼嵌入至 JavaScript 屬性中:

renderer.RenderingOptions.JavaScript = @"
    var style = document.createElement('style');
    style.textContent = 'body > *:not(#invoice-summary) { display: none !important; }';
    document.head.appendChild(style);
";
renderer.RenderingOptions.JavaScript = @"
    var style = document.createElement('style');
    style.textContent = 'body > *:not(#invoice-summary) { display: none !important; }';
    document.head.appendChild(style);
";
renderer.RenderingOptions.JavaScript = "
    var style = document.createElement('style');
    style.textContent = 'body > *:not(#invoice-summary) { display: none !important; }';
    document.head.appendChild(style);
"
$vbLabelText   $csharpLabel

當我們能控制原始 HTML 時,@media print 規則提供了最輕量級的替代方案——無外部依賴項,無執行時注入:

@media print {
    header, nav, footer, .sidebar { display: none !important; }
    #invoice-summary { width: 100%; margin: 0; }
}

請在渲染器中將 CssMediaType 設為 PdfCssMediaType.Print 以啟用這些規則:

renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print
$vbLabelText   $csharpLabel

此方案特別適用於表單區塊列印情境,即應用程式已預先定義列印專用版面配置的情況。 保險理賠表單、多步驟精靈及結帳摘要頁面,通常會採用 @media print 規則,在將相關內容區塊擴展至全寬的同時,隱藏導覽列與進度指示器。

CSS 的這種做法有一個重要的限制:如果 display: none 被應用在錯誤的特定性層級,隱藏元素仍會在文件流中佔用空間。 請務必使用 !important 來覆寫框架樣式(如 Bootstrap、Tailwind),以免元素在特定斷點處重新顯示。 對於深度嵌套的目標元素,使用更精確的選擇器可避免附帶元素被隱藏:

body > *:not(#target),
body > *:not(#target) ~ * {
    display: none !important;
}

如何在伺服器端擷取 HTML 片段?

當我們能夠取得原始 HTML(無論是從檔案、資料庫、內容管理系統或 HTTP 回應中讀取)時,最簡潔的做法是使用 HTML 解析器在伺服器端提取目標元素,然後將該片段傳遞給 RenderHtmlAsPdf()。 不使用 JavaScript、不注入 CSS、不進行執行時 DOM 操作。

AngleSharp 是此模式下標準的 .NET HTML 解析器:

using IronPdf;
using AngleSharp;
using AngleSharp.Html.Parser;

string fullPageHtml = @"
<html>
<head>
    <style>
        table { border-collapse: collapse; width: 100%; }
        td, th { border: 1px solid #ddd; padding: 8px; text-align: left; }
    </style>
</head>
<body>
    <header><h1>Dashboard</h1></header>
    <div id='revenue-widget'>
        <h3>Q4 Revenue</h3>
        <table>
            <tr><th>Month</th><th>Revenue</th></tr>
            <tr><td>October</td><td>$1.2M</td></tr>
            <tr><td>November</td><td>$1.5M</td></tr>
            <tr><td>December</td><td>$1.8M</td></tr>
        </table>
    </div>
    <div id='other-content'>Other widgets...</div>
</body>
</html>";

// Parse and extract the target element
var parser = new HtmlParser();
var document = parser.ParseDocument(fullPageHtml);
var targetElement = document.QuerySelector("#revenue-widget");

if (targetElement is null)
{
    Console.WriteLine("Target element not found.");
    return;
}

// Wrap the fragment in a minimal HTML document to preserve styles
string fragmentHtml = $@"
<html>
<head>
    <style>
        table {{ border-collapse: collapse; width: 100%; }}
        td, th {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
    </style>
</head>
<body>
    {targetElement.OuterHtml}
</body>
</html>";

var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml);
pdf.SaveAs("revenue-widget.pdf");
using IronPdf;
using AngleSharp;
using AngleSharp.Html.Parser;

string fullPageHtml = @"
<html>
<head>
    <style>
        table { border-collapse: collapse; width: 100%; }
        td, th { border: 1px solid #ddd; padding: 8px; text-align: left; }
    </style>
</head>
<body>
    <header><h1>Dashboard</h1></header>
    <div id='revenue-widget'>
        <h3>Q4 Revenue</h3>
        <table>
            <tr><th>Month</th><th>Revenue</th></tr>
            <tr><td>October</td><td>$1.2M</td></tr>
            <tr><td>November</td><td>$1.5M</td></tr>
            <tr><td>December</td><td>$1.8M</td></tr>
        </table>
    </div>
    <div id='other-content'>Other widgets...</div>
</body>
</html>";

// Parse and extract the target element
var parser = new HtmlParser();
var document = parser.ParseDocument(fullPageHtml);
var targetElement = document.QuerySelector("#revenue-widget");

if (targetElement is null)
{
    Console.WriteLine("Target element not found.");
    return;
}

// Wrap the fragment in a minimal HTML document to preserve styles
string fragmentHtml = $@"
<html>
<head>
    <style>
        table {{ border-collapse: collapse; width: 100%; }}
        td, th {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
    </style>
</head>
<body>
    {targetElement.OuterHtml}
</body>
</html>";

var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml);
pdf.SaveAs("revenue-widget.pdf");
Imports IronPdf
Imports AngleSharp
Imports AngleSharp.Html.Parser

Dim fullPageHtml As String = "
<html>
<head>
    <style>
        table { border-collapse: collapse; width: 100%; }
        td, th { border: 1px solid #ddd; padding: 8px; text-align: left; }
    </style>
</head>
<body>
    <header><h1>Dashboard</h1></header>
    <div id='revenue-widget'>
        <h3>Q4 Revenue</h3>
        <table>
            <tr><th>Month</th><th>Revenue</th></tr>
            <tr><td>October</td><td>$1.2M</td></tr>
            <tr><td>November</td><td>$1.5M</td></tr>
            <tr><td>December</td><td>$1.8M</td></tr>
        </table>
    </div>
    <div id='other-content'>Other widgets...</div>
</body>
</html>"

' Parse and extract the target element
Dim parser As New HtmlParser()
Dim document = parser.ParseDocument(fullPageHtml)
Dim targetElement = document.QuerySelector("#revenue-widget")

If targetElement Is Nothing Then
    Console.WriteLine("Target element not found.")
    Return
End If

' Wrap the fragment in a minimal HTML document to preserve styles
Dim fragmentHtml As String = $"
<html>
<head>
    <style>
        table {{ border-collapse: collapse; width: 100%; }}
        td, th {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
    </style>
</head>
<body>
    {targetElement.OuterHtml}
</body>
</html>"

Dim renderer As New ChromePdfRenderer()
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(fragmentHtml)
pdf.SaveAs("revenue-widget.pdf")
$vbLabelText   $csharpLabel

關鍵細節在於將擷取的片段封裝在完整的 HTML 文件中,並使用相關的 <style><link> 標籤。 若未使用此封裝層,內嵌樣式雖能正確渲染,但外部樣式表與繼承的 CSS 規則將無法保留。針對電子郵件範本預覽渲染(此時範本 HTML 已儲存為字串),此提取模式能呈現像素級精準的結果,因為我們能完全掌控渲染內容的每個細節。

若將 HtmlAgilityPack 作為替代解析器,同樣的模式亦適用:

using HtmlAgilityPack;
using IronPdf;

var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(fullPageHtml);

var targetNode = htmlDoc.DocumentNode.SelectSingleNode("//*[@id='revenue-widget']");
if (targetNode is null)
{
    Console.WriteLine("Target element not found.");
    return;
}

string fragmentHtml = $"<html><body>{targetNode.OuterHtml}</body></html>";

var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml);
pdf.SaveAs("revenue-widget-hap.pdf");
using HtmlAgilityPack;
using IronPdf;

var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(fullPageHtml);

var targetNode = htmlDoc.DocumentNode.SelectSingleNode("//*[@id='revenue-widget']");
if (targetNode is null)
{
    Console.WriteLine("Target element not found.");
    return;
}

string fragmentHtml = $"<html><body>{targetNode.OuterHtml}</body></html>";

var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml);
pdf.SaveAs("revenue-widget-hap.pdf");
Imports HtmlAgilityPack
Imports IronPdf

Dim htmlDoc As New HtmlDocument()
htmlDoc.LoadHtml(fullPageHtml)

Dim targetNode = htmlDoc.DocumentNode.SelectSingleNode("//*[@id='revenue-widget']")
If targetNode Is Nothing Then
    Console.WriteLine("Target element not found.")
    Return
End If

Dim fragmentHtml As String = $"<html><body>{targetNode.OuterHtml}</body></html>"

Dim renderer As New ChromePdfRenderer()
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(fragmentHtml)
pdf.SaveAs("revenue-widget-hap.pdf")
$vbLabelText   $csharpLabel

選擇 AngleSharp 或 HtmlAgilityPack 主要取決於個人偏好。 AngleSharp 使用 CSS 選擇器 (QuerySelector),這與前端開發者的思維模式相符。 HtmlAgilityPack 使用 XPath (SelectSingleNode),這在以 XML 為主的 .NET 程式碼庫中較為常見。

針對電子郵件範本的預覽渲染——即範本 HTML 以字串形式儲存於資料庫或內容管理系統 (CMS) 中——伺服器端擷取能提供像素級精準的結果,因為我們能完全掌控渲染內容的每個細節。 我們亦可使用 RenderHtmlAsPdf(string Html, string BaseUrlOrPath),並將第二個參數指向本地資源目錄,以確保透過相對路徑引用的圖片和樣式表能正確解析:

PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml, @"C:\templates\assets\");
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml, @"C:\templates\assets\");
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(fragmentHtml, "C:\templates\assets\")
$vbLabelText   $csharpLabel

相較於 JavaScript DOM 隔離,其取捨在於伺服器端擷取無法處理需要客戶端渲染的內容(例如 JavaScript 生成的元素、單頁應用程式 (SPA) 元件,以及透過 API 擷取的資料)。 若 HTML 內容包含由 React 或 Vue 應用程式在執行時填入的 <div id="app"></div>,則提取的片段將為空。 在這些情況下,請採用方法 1 或 4。

渲染即時網址時,該如何鎖定目標元素?

對於無法存取原始 HTML 的即時網址(例如第三方儀表板、外部報告、託管應用程式),我們會將 RenderUrlAsPdf()JavaScript 屬性及 WaitFor 結合使用,以便在頁面載入後隔離特定區段。

此為儀表板小工具匯出情境:某 BI 工具在網頁上渲染圖表與表格,我們需要將單一小工具匯出為 PDF 格式,以便分發給相關人員。

using IronPdf;

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;

// Wait for the dashboard widget to render (async content)
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("[data-widget='revenue-chart']", 15000);

// Isolate the widget after it renders
renderer.RenderingOptions.JavaScript = @"
    var widget = document.querySelector('[data-widget=""revenue-chart""]');
    if (widget) {
        // Preserve computed styles by cloning into a clean body
        document.body.innerHTML = '';
        document.body.appendChild(widget);
    }
";

PdfDocument pdf = renderer.RenderUrlAsPdf("https://dashboard.example.com/q4-report");
pdf.SaveAs("revenue-chart-export.pdf");
using IronPdf;

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;

// Wait for the dashboard widget to render (async content)
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("[data-widget='revenue-chart']", 15000);

// Isolate the widget after it renders
renderer.RenderingOptions.JavaScript = @"
    var widget = document.querySelector('[data-widget=""revenue-chart""]');
    if (widget) {
        // Preserve computed styles by cloning into a clean body
        document.body.innerHTML = '';
        document.body.appendChild(widget);
    }
";

PdfDocument pdf = renderer.RenderUrlAsPdf("https://dashboard.example.com/q4-report");
pdf.SaveAs("revenue-chart-export.pdf");
Imports IronPdf

Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.EnableJavaScript = True

' Wait for the dashboard widget to render (async content)
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("[data-widget='revenue-chart']", 15000)

' Isolate the widget after it renders
renderer.RenderingOptions.JavaScript = "
    var widget = document.querySelector('[data-widget=""revenue-chart""]);
    if (widget) {
        // Preserve computed styles by cloning into a clean body
        document.body.innerHTML = '';
        document.body.appendChild(widget);
    }
"

Dim pdf As PdfDocument = renderer.RenderUrlAsPdf("https://dashboard.example.com/q4-report")
pdf.SaveAs("revenue-chart-export.pdf")
$vbLabelText   $csharpLabel

WaitFor.HtmlQuerySelector() 呼叫可確保在 JavaScript 執行前,該元件已存在於 DOM 中。 15 秒的超時設定可因應更新儀表板資料時較慢的 API 呼叫。 隨後,JavaScript 會將頁面精簡為僅剩小工具。

對於具有複雜 CSS 依賴關係的頁面,採用 appendChild 的方法(移動節點而非複製其 outerHTML)能保留更多計算出的樣式,因為元素在 CSSOM 中仍維持其原始位置。 方法 1 中採用 innerHTML 的替換方式雖然較為簡單,但可能會遺失依賴於祖先選擇器的樣式。

當目標頁面需要驗證時,請在呼叫 RenderUrlAsPdf() 之前於渲染器上設定 Cookie:

renderer.RenderingOptions.CustomCookies = new Dictionary<string, string>
{
    { "session_id", "abc123" },
    { "auth_token", "bearer-xyz" }
};
renderer.RenderingOptions.CustomCookies = new Dictionary<string, string>
{
    { "session_id", "abc123" },
    { "auth_token", "bearer-xyz" }
};
Imports System.Collections.Generic

renderer.RenderingOptions.CustomCookies = New Dictionary(Of String, String) From {
    {"session_id", "abc123"},
    {"auth_token", "bearer-xyz"}
}
$vbLabelText   $csharpLabel

WaitFor 類別提供了超越 HtmlQuerySelector() 的額外等待策略。 NetworkIdle0() 會等待所有網路請求完成且無未處理連線後才結束 — 適用於從多個 API 端點載入資料的儀表板。 NetworkIdle2() 最多可容許兩組未關閉的連線,這有助於處理具有持久 WebSocket 連線或長輪詢的網頁。 JavaScript() 等待頁面呼叫 window.ironpdf.notifyRender() —— 當我們能控制目標頁面,並在所有資料載入及動畫完成後明確發出渲染就緒訊號時,這是最精確的選項。

針對定期執行的儀表板匯出任務(例如:每晚生成 PDF 供寄送給利害關係人),請將渲染程序封裝在一個能攔截超時例外狀況的重試迴圈中。 若 WaitFor 超過其 maxWaitTime,IronPDF 將繼續渲染現有的內容 — 該內容可能不完整。 延長超時設定或切換至 NetworkIdle0() 通常可解決在網速較慢的網路環境中出現的間歇性失敗問題。

四種方法的比較

翻譯方針 最適合 需要原始 HTML 檔案 JS 依賴項 複雜度
JavaScript DOM 隔離 從任何來源進行通用元素擷取 語言
CSS 注入 在不修改 DOM 的情況下隱藏區塊; @media print 版面配置 部分內容(CustomCssUrl 需搭配 RenderHtmlAsPdf 使用) 否(除非透過 JavaScript 注入 URL)
伺服器端片段擷取 CMS 內容、儲存的範本、電子郵件預覽 低–中
透過 JS 定位進行 URL 渲染 即時儀表板、第三方頁面、單頁應用程式 (SPA) 小工具 中至高

選擇合適的方法

此決策取決於兩個因素:我們是否能取得原始 HTML 碼,以及目標內容是否需要透過 JavaScript 進行渲染。

發票明細擷取是最常見的應用情境。 當發票 HTML 是在伺服器端生成時(例如 Razor 檢視、Handlebars 範本或儲存的 HTML 字串),方法 3(伺服器端擷取)能提供最乾淨的結果,且完全沒有執行時開銷。 提取 #line-items 表格,將其封裝在帶有樣式的 HTML 外殼中,並進行渲染。

儀表板小工具的匯出功能需要執行 JavaScript,因為小工具的內容是在初始頁面載入後透過 API 呼叫所填入的。 方法 1(JS DOM 隔離)會在儀表板於本地執行或處於驗證環境時處理此情況。 當儀表板為第三方託管應用程式且我們僅持有其 URL 時,必須採用方法 4(透過 JS 定位進行 URL 渲染)。

表單區段列印 — 從多步驟表單中擷取特定區段供使用者檢視或符合規範的歸檔 — 若應用程式已定義 @media print 規則,則自然適用於方法 2(CSS 注入);若表單 HTML 是在伺服器端組裝的,則適用於方法 3。

電子郵件範本預覽渲染——即在發送前生成 HTML 電子郵件範本的 PDF 預覽——屬於純粹的"方法 3"情境。 HTML 範本為儲存的字串,外部資源(圖片、字型)存放於已知的 URL,且 BaseUrlOrPath 上的 RenderHtmlAsPdf() 參數會解析所有相對路徑。

對於需要支援多種情境的應用程式,請將渲染邏輯封裝在一個接受策略參數的服務介面中:

public enum ElementExtractionStrategy
{
    JavaScriptIsolation,
    CssInjection,
    ServerSideExtraction,
    UrlWithJsTargeting
}
public enum ElementExtractionStrategy
{
    JavaScriptIsolation,
    CssInjection,
    ServerSideExtraction,
    UrlWithJsTargeting
}
Public Enum ElementExtractionStrategy
    JavaScriptIsolation
    CssInjection
    ServerSideExtraction
    UrlWithJsTargeting
End Enum
$vbLabelText   $csharpLabel

這讓呼叫程式碼能根據輸入類型選擇適當的方法,無需重複設定渲染器。

後續步驟

IronPDF 中的 HTML 元素隔離屬於渲染時的問題,並非內建 API 功能。 上述四種方法涵蓋了完整的應用範圍——從伺服器端的範本擷取(零 JavaScript,輸出最簡潔)到即時 URL 定位(完整執行 JavaScript,支援單頁應用程式與非同步內容)。 比較表提供快速參考,而實際應用情境則將常見的商業需求與適當的策略相互對應。

針對生產環境部署的幾項額外考量:

效能:伺服器端擷取(方法 3)速度最快,因為它完全跳過了 JavaScript 的執行。 基於 JavaScript 的方法(第 1 項和第 4 項)會產生與頁面複雜度及 WaitFor 超時時間成正比的額外開銷。 針對批次處理(例如:生成 500 份發票 PDF 檔),透過 Parallel.ForEach 進行伺服器端擷取並搭配多個 ChromePdfRenderer 實例,可提供最佳的處理效能。

除錯:若 PDF 輸出為空白或內容遺漏,請啟用 EnableJavaScript = true 並增加 WaitFor 的超時設定。 若目標元素依賴非同步資料,WaitFor.NetworkIdle0() 比固定的 RenderDelay 更為可靠。 渲染選項指南涵蓋了影響版面配置的視口寬度與紙張適配設定。

策略結合:混合使用多種策略並無不可。 我們可以利用伺服器端擷取技術,從多個片段(例如:來自一個來源的頁首、來自另一個來源的資料表、來自第三個來源的圖表 SVG)建構出一個複合 HTML 文件,然後將組裝好的文件渲染為單一 PDF 檔案。 RenderHtmlAsPdf(string Html, string BaseUrlOrPath) 方法可根據基礎 URL 解析相對資產路徑,使從異質來源組合文件變得輕而易舉。

請參閱 JavaScript 轉 PDF 實作指南以了解進階的 JS 執行模式、WaitFor 文件以掌握所有可用的等待策略、渲染選項指南以了解完整的 ChromePdfRenderOptions 介面,以及自訂 JavaScript 程式碼範例以獲取可直接執行的程式碼片段。

查看起價 $749 的授權方案ChromePdfRenderOptions API 參考文件WaitFor API 參考文件詳列了所有屬性與方法。

常見問題解答

轉換HTML元素為PDF的主要方法有哪些?

主要方法包括 JavaScript 隔離、CSS 隱藏、伺服器端擷取以及即時 URL 定位,所有這些功能皆可透過 IronPDF 實現。

在 HTML 轉 PDF 的情境中,JS 隔離機制是如何運作的?

JS 隔離是指在將 HTML 文件轉換為 PDF 之前,先執行 JavaScript 來動態操作該文件。這可透過 IronPDF 來實現,以確保僅渲染特定元素。

何謂 CSS 隱藏,以及它在 PDF 轉換中如何被運用?

CSS 隱藏是指利用 CSS 樣式來隱藏不應出現在 PDF 中的元素。IronPDF 支援此功能,允許開發人員在轉換過程中指定樣式表或樣式規則。

IronPDF 能否在伺服器端擷取特定的 HTML 元素來生成 PDF?

是的,IronPDF 可在伺服器端擷取特定的 HTML 元素,讓您能精確控制網頁的哪些部分將轉換為 PDF。

在 HTML 轉 PDF 的過程中,即時 URL 定位有何優勢?

透過即時網址轉譯功能,IronPDF 能直接將即時網頁網址中的元素轉換為 PDF,確保擷取到最新內容,無需使用本機 HTML 檔案。

是否可以使用 IronPDF 將網頁的某個區段轉換為 PDF?

是的,IronPDF 提供將網頁的特定區段或元素轉換為 PDF 的功能,讓您能輕鬆聚焦於相關內容。

IronPDF 在 HTML 轉 PDF 過程中如何處理動態內容?

IronPDF 能在轉換過程中執行 JavaScript 以渲染動態內容,確保依賴客戶端腳本的元素能在 PDF 中準確呈現。

Curtis Chau
技術作家

Curtis Chau 擁有卡爾頓大學計算機科學學士學位,專注於前端開發,擅長於 Node.js、TypeScript、JavaScript 和 React。Curtis 熱衷於創建直觀且美觀的用戶界面,喜歡使用現代框架並打造結構良好、視覺吸引人的手冊。

除了開發之外,Curtis 對物聯網 (IoT) 有著濃厚的興趣,探索將硬體和軟體結合的創新方式。在閒暇時間,他喜愛遊戲並構建 Discord 機器人,結合科技與創意的樂趣。

準備好開始了嗎?
Nuget 下載 18,332,619 | 版本: 2026.4 剛剛發布
Still Scrolling Icon

還在捲動嗎?

想要快速證明? PM > Install-Package IronPdf
執行範例 觀看您的 HTML 變成 PDF。