DEV Community

IronSoftware
IronSoftware

Posted on

HTML to PDF with Responsive CSS in C# (.NET Guide)

Responsive CSS designed for screens often breaks in PDFs — multi-column layouts collapse, navigation menus disappear, mobile breakpoints activate incorrectly. I've debugged invoice systems where PDFs rendered in single-column mobile layouts despite targeting A4 paper, reports where CSS Grid layouts collapsed into vertical stacks, and documentation where @media print stylesheets were ignored entirely.

The root cause: PDF rendering uses different CSS media types than browsers. Browsers default to screen media type (optimized for displays). Print operations use print media type (optimized for paper). Many developers write CSS assuming screen rendering, then wonder why PDFs look wrong — the rendering engine applies different CSS rules for print media.

Understanding CSS media types solves most PDF layout issues. Modern CSS supports @media screen (digital displays) and @media print (printers, PDF). Define screen styles for web viewing, print styles for PDF output. IronPDF lets you choose which media type to apply during rendering — PdfCssMediaType.Screen (default) or PdfCssMediaType.Print.

The practical implication: if your HTML looks correct in a browser but breaks in PDF, you're likely hitting media type mismatches. Test HTML with browser print preview (Ctrl+P / Cmd+P) — if print preview looks broken, PDF will too. Fix CSS for print media type, PDFs render correctly.

using IronPdf;
// Install via NuGet: Install-Package IronPdf

var renderer = new ChromePdfRenderer();

// Use print CSS media type for PDF-optimized rendering
renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print;

var html = @"
<!DOCTYPE html>
<html>
<head>
    <style>
        @media screen {
            body { background-color: #f3f4f6; }
            nav { display: block; }
        }

        @media print {
            body { background-color: white; }
            nav { display: none; }
            table thead { display: table-header-group; }
        }
    </style>
</head>
<body>
    <nav>Website Navigation</nav>
    <table>
        <thead>
            <tr><th>Column</th></tr>
        </thead>
        <tbody>
            <tr><td>Data</td></tr>
        </tbody>
    </table>
</body>
</html>
";

var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("report.pdf");
Enter fullscreen mode Exit fullscreen mode

With CssMediaType = Print, the navigation hides (nav { display: none; }), background becomes white (print-optimized), and table headers repeat on each page (thead { display: table-header-group; }). These are print-specific optimizations browsers apply automatically during printing.

What NuGet Packages Do I Need?

Install IronPDF via Package Manager Console:

Install-Package IronPdf
Enter fullscreen mode Exit fullscreen mode

Or .NET CLI:

dotnet add package IronPdf
Enter fullscreen mode Exit fullscreen mode

IronPDF includes CSS media type handling in the core library.

Why Do Table Headers Need Special Handling?

Multi-page tables in PDFs should repeat headers at the top of each page — like printed spreadsheets. This requires @media print CSS and semantic HTML:

var html = @"
<style>
    @media print {
        table thead { display: table-header-group; }
        table tfoot { display: table-footer-group; }
    }
</style>

<table>
    <thead>
        <tr>
            <th>Product</th>
            <th>Price</th>
        </tr>
    </thead>
    <tbody>
        <!-- 100 rows... -->
    </tbody>
    <tfoot>
        <tr>
            <td>Total:</td>
            <td>$12,345</td>
        </tr>
    </tfoot>
</table>
";

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print;

var pdf = renderer.RenderHtmlAsPdf(html);
Enter fullscreen mode Exit fullscreen mode

Without CssMediaType.Print, headers don't repeat. With it enabled, <thead> rows repeat at the top of every PDF page containing table content. <tfoot> rows repeat at the bottom.

I generate financial reports this way — 50-page tables with headers showing column labels on every page. Users can print any page individually and still see what each column represents.

What's the Difference Between Screen and Print Media Types?

Screen Media Type (PdfCssMediaType.Screen, default):

  • Preserves navigation, sidebars, interactive elements
  • Uses screen-optimized colors (often darker backgrounds)
  • Respects responsive breakpoints as if viewing on desktop
  • Preserves animations, hover effects (static in PDF but CSS loads)
  • Suitable for web page archival, "Save as PDF" functionality

Print Media Type (PdfCssMediaType.Print):

  • Hides navigation, sidebars, footers (content-focused)
  • Uses print-optimized colors (white backgrounds, dark text for readability)
  • Applies print-specific layouts (multi-column for newspaper style)
  • Enables repeating table headers/footers
  • Suitable for reports, invoices, printable documents

Choose based on use case: archiving web pages as-displayed → Screen. Generating reports for printing → Print.

How Do I Write CSS for Both Screen and Print?

Use @media queries to define separate styles:

/* Base styles (apply to both) */
body {
    font-family: Arial, sans-serif;
    font-size: 12pt;
}

/* Screen-only styles */
@media screen {
    body {
        background-color: #1a1a1a;
        color: #ffffff;
    }

    .sidebar {
        display: block;
    }

    .page-break {
        display: none;
    }
}

/* Print-only styles */
@media print {
    body {
        background-color: white;
        color: black;
    }

    .sidebar {
        display: none;
    }

    .page-break {
        page-break-after: always;
    }

    a[href]:after {
        content: " (" attr(href) ")";
    }
}
Enter fullscreen mode Exit fullscreen mode

This CSS adapts: dark mode for screens, white for print. Sidebars visible on screen, hidden in print. Page breaks ignored on screen, enforced in print. Links show URLs when printed.

I use this pattern for documentation systems — users read docs online (screen media), print specific sections (print media optimized with page breaks, no navigation clutter).

How Do I Handle Responsive Breakpoints in PDFs?

Responsive CSS uses viewport width to adapt layouts (@media (max-width: 768px)). PDFs have fixed page widths (A4 is 210mm ~= 595px at 72 DPI). If your mobile breakpoint is 768px, A4 pages may trigger it unexpectedly.

Set viewport width explicitly to avoid mobile layouts:

renderer.RenderingOptions.ViewPortWidth = 1024; // Desktop viewport
Enter fullscreen mode Exit fullscreen mode

This forces the renderer to treat content as if viewed on a 1024px wide screen, applying desktop CSS even though PDF page is narrower.

For completely custom PDF layouts, use print media type with dedicated print stylesheets:

@media print {
    .container {
        width: 100%;
        max-width: none;
    }

    .mobile-menu {
        display: none !important;
    }
}
Enter fullscreen mode Exit fullscreen mode

What About Modern CSS Features (Grid, Flexbox)?

Chromium-based rendering supports CSS Grid, Flexbox, custom properties (CSS variables), modern selectors. If CSS works in Chrome browser, IronPDF renders it identically.

@media print {
    .report-layout {
        display: grid;
        grid-template-columns: 1fr 1fr;
        grid-gap: 20px;
    }
}
Enter fullscreen mode Exit fullscreen mode

This creates two-column print layouts using CSS Grid — fully supported.

Bootstrap, Tailwind CSS, Foundation all work as long as stylesheets are accessible (embedded, or via BaseUrlOrPath for external CSS files).

How Does IronPDF Compare to wkhtmltopdf for Print CSS?

wkhtmltopdf uses WebKit from 2016 — before many modern CSS features stabilized. Its print media support is buggy:

  • Table headers don't repeat reliably
  • CSS Grid partially broken
  • Custom properties (CSS variables) unsupported
  • Some @media print rules ignored

IronPDF uses Chromium, matching current Chrome browser capabilities:

  • Full @media print support
  • Reliable table header repetition with <thead>
  • Complete CSS Grid and Flexbox
  • Custom properties, modern selectors, everything

I migrated a reporting system from wkhtmltopdf specifically because table headers failed to repeat on multi-page reports. Switching to IronPDF with CssMediaType.Print fixed it immediately — headers repeated correctly on all pages.

What Common Issues Should I Watch For?

Page break forcing: Use page-break-after: always or page-break-before: always in print CSS to control pagination:

@media print {
    .section {
        page-break-after: always;
    }
}
Enter fullscreen mode Exit fullscreen mode

Avoid breaking inside elements: Use page-break-inside: avoid to prevent page breaks within tables, images, or sections:

@media print {
    table {
        page-break-inside: avoid;
    }
}
Enter fullscreen mode Exit fullscreen mode

Testing print layouts: Always test HTML with browser print preview (Ctrl+P / Cmd+P) before generating PDFs. If print preview looks broken, PDF will too.

Default media type: IronPDF defaults to Screen. Remember to explicitly set CssMediaType.Print for reports requiring print-optimized layouts.

I've debugged issues where developers assumed Print was default, generated PDFs with screen-optimized CSS (navigation, sidebars, dark backgrounds), and wondered why PDFs looked unprofessional. Explicitly setting media type prevents assumptions.

Quick Reference

CSS Feature Screen Media Print Media Use Case
Navigation/Sidebars Visible Hidden Content focus in print
Background colors Any color White/light Print ink savings
Table headers Normal Repeat on pages Multi-page tables
Page breaks Ignored Enforced Section separation
Links Clickable Show URLs Print reference
Responsive breakpoints Active Often disabled Fixed page sizes
Multi-column Flex/Grid Print columns Newspaper layouts

Key Principles:

  • CssMediaType.Screen (default) preserves web appearance, CssMediaType.Print optimizes for printing
  • Use @media print CSS for print-specific styles (hide navigation, white backgrounds, page breaks)
  • Table headers repeat only with CssMediaType.Print + <thead> tags + display: table-header-group
  • Test HTML with browser print preview before generating PDFs
  • IronPDF's Chromium engine fully supports modern CSS (Grid, Flexbox, variables)
  • wkhtmltopdf has broken print media support — avoid for new projects
  • Set ViewPortWidth to control responsive breakpoints in fixed-width PDFs
  • Use page-break-after, page-break-before, page-break-inside for pagination control

The complete responsive CSS guide includes examples for complex layouts and print optimization patterns.


*Written by Jacob Mellor, CTO at Iron Software. Jacob created IronPDF and leads a team of 50+ engineers building .NET document processing libraries.

Top comments (0)