DEV Community

IronSoftware
IronSoftware

Posted on

iText pdfHTML CSS Flexbox Not Working (Issue Fixed)

Developers using iText 7's pdfHTML add-on discover that CSS Flexbox layouts do not render correctly. Elements positioned with display: flex collapse or misalign, breaking modern responsive designs. This limitation affects developers who design HTML templates with current CSS practices. This article documents the CSS support gaps and examines alternatives with complete CSS3 support.

The Problem

iText's pdfHTML add-on converts HTML and CSS to PDF, but its CSS engine does not fully implement CSS3 specifications. Flexbox, CSS Grid, and other modern layout features either do not work or produce incorrect output.

When HTML containing Flexbox is processed:

  • display: flex may be ignored entirely
  • justify-content and align-items have no effect
  • Flex items stack vertically instead of horizontally
  • flex-wrap does not wrap items correctly

Error Messages and Symptoms

There are typically no errors - the layout simply renders incorrectly:

/* This layout works in browsers but breaks in pdfHTML */
.container {
    display: flex;
    justify-content: space-between;
    align-items: center;
}
Enter fullscreen mode Exit fullscreen mode

Output shows:

  • Items stacked vertically instead of side-by-side
  • No spacing between elements
  • Alignment properties ignored

Developers often discover this only after building complete HTML templates.

Who Is Affected

This issue impacts developers using modern CSS:

Use Cases: Invoice generation, report templates, document automation, any PDF generation using HTML designed for web.

CSS Features Not Supported:

  • display: flex and Flexbox properties
  • display: grid and CSS Grid
  • CSS custom properties (variables)
  • Modern pseudo-selectors

Evidence from the Developer Community

From iText documentation and community reports:

"pdfHTML supports a subset of CSS. Some CSS3 properties are not implemented."
— iText Documentation

"My template works in the browser but the layout is completely wrong in the generated PDF."
— Developer report, 2023

Comprehensive CSS Support Matrix

The following matrix documents CSS feature support in iText pdfHTML based on official documentation and developer reports:

Layout Features

CSS Feature pdfHTML Support Notes
display: flex Not supported Elements render as block
display: grid Not supported Elements render as block
display: inline-flex Not supported Elements render as inline
flex-direction Not supported -
flex-wrap Not supported -
justify-content Not supported -
align-items Not supported -
align-self Not supported -
flex-grow/shrink Not supported -
grid-template-columns Not supported -
grid-gap / gap Not supported -
position: sticky Not supported Falls back to relative
position: fixed Limited May not work as expected

CSS3 Features

CSS Feature pdfHTML Support Notes
CSS Variables (--custom) Not supported Variables not resolved
calc() Limited Simple expressions only
@media queries Limited Print media partially supported
@font-face Limited Requires specific configuration
@keyframes / animations Not supported Static output only
transform Limited Basic transforms only
transition Not supported -
filter Not supported -
backdrop-filter Not supported -
clip-path Not supported -

Box Model and Sizing

CSS Feature pdfHTML Support Notes
box-sizing Supported -
min-width/height Supported -
max-width/height Supported -
margin Supported -
padding Supported -
border Supported -
border-radius Limited May not render correctly
box-shadow Limited Basic shadows only

Pseudo-elements and Selectors

CSS Feature pdfHTML Support Notes
::before / ::after Limited Basic support
:nth-child() Supported -
:hover / :focus Not applicable No interactivity
::placeholder Not supported -
:has() Not supported -
:where() / :is() Not supported -

Root Cause Analysis

pdfHTML uses a custom CSS engine built specifically for PDF generation, not a browser rendering engine. This architectural choice has significant implications for CSS support.

Why Flexbox and Grid Are Missing

Implementing CSS Flexbox and Grid requires:

  1. Complete CSS specification parsing: The Flexbox specification alone is over 100 pages of layout algorithms
  2. Layout algorithm implementation: Each layout mode (flex, grid, table, block, inline) requires separate implementation
  3. Box model calculations: Nested layouts with different display modes must interact correctly
  4. Intrinsic sizing: Flex and grid items have complex minimum/maximum size calculations
  5. Alignment algorithms: justify-content, align-items, and related properties require precise positioning

Implementing these features to browser-specification compliance would essentially mean building a browser rendering engine. iText's core product focus is PDF manipulation (creation, editing, form filling, extraction), not web rendering.

The pdfHTML Scope

pdfHTML is positioned as a commercial add-on that converts "simple HTML and CSS" to PDF. From iText's perspective:

  • Documents with basic formatting (headings, paragraphs, tables, lists)
  • Inline styles and simple external stylesheets
  • Basic positioning with floats and absolute positioning
  • Print-oriented layouts designed for PDF output

This scope explicitly excludes:

  • Modern web layouts designed for browsers
  • Single-page application (SPA) rendering
  • JavaScript-generated content
  • Responsive designs that adapt to viewport

Why This Matters for Developers

Modern web development has shifted to Flexbox and Grid as primary layout mechanisms:

/* Common modern patterns that don't work in pdfHTML */

/* Navigation bar */
.navbar {
    display: flex;
    justify-content: space-between;
}

/* Card grid */
.cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 20px;
}

/* Centered content */
.center {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
}
Enter fullscreen mode Exit fullscreen mode

Developers who build templates for web viewing expect these patterns to work in PDF output.

Attempted Workarounds

Workaround 1: Use Tables Instead of Flexbox

Approach: Replace Flexbox layouts with HTML tables.

<!-- Instead of Flexbox -->
<div style="display: flex; justify-content: space-between;">
    <div>Left</div>
    <div>Right</div>
</div>

<!-- Use tables -->
<table style="width: 100%;">
    <tr>
        <td style="text-align: left;">Left</td>
        <td style="text-align: right;">Right</td>
    </tr>
</table>
Enter fullscreen mode Exit fullscreen mode

Limitations:

  • Requires rewriting templates
  • Tables have semantic issues
  • Complex nested layouts become unwieldy
  • Not a one-to-one replacement for Flexbox capabilities

Workaround 2: Maintain Separate PDF Templates

Approach: Create simplified templates specifically for PDF generation.

Limitations:

  • Doubles template maintenance effort
  • Visual inconsistency between web and PDF
  • Changes must be made in two places

Workaround 3: Use Inline Styles and Absolute Positioning

Approach: Use explicit widths and absolute positioning.

<div style="position: relative; height: 50px;">
    <div style="position: absolute; left: 0;">Left</div>
    <div style="position: absolute; right: 0;">Right</div>
</div>
Enter fullscreen mode Exit fullscreen mode

Limitations:

  • Fragile and hard to maintain
  • Does not scale to complex layouts
  • Manual pixel calculations required

A Different Approach: IronPDF

IronPDF uses Chromium for rendering, providing complete CSS3 support including Flexbox and Grid.

Why IronPDF Supports Modern CSS

IronPDF embeds the same Chromium engine used in Google Chrome. This means:

  1. Complete CSS3: Every CSS feature Chrome supports, IronPDF supports
  2. Flexbox and Grid: Modern layouts work exactly as in the browser
  3. CSS Variables: Custom properties work correctly
  4. Media Queries: Print-specific styles are respected

Code Example

using IronPdf;

public class ModernLayoutGenerator
{
    public byte[] GenerateFlexboxDocument()
    {
        var renderer = new ChromePdfRenderer();

        string html = @"
<!DOCTYPE html>
<html>
<head>
    <style>
        :root {
            --primary-color: #2563eb;
            --spacing: 20px;
        }

        body {
            font-family: 'Segoe UI', Arial, sans-serif;
            margin: 0;
            padding: var(--spacing);
        }

        .header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: var(--spacing);
            background: var(--primary-color);
            color: white;
        }

        .card-container {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: var(--spacing);
            margin-top: var(--spacing);
        }

        .card {
            display: flex;
            flex-direction: column;
            padding: var(--spacing);
            border: 1px solid #ddd;
            border-radius: 8px;
        }

        .card-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            border-bottom: 1px solid #eee;
            padding-bottom: 10px;
            margin-bottom: 10px;
        }

        .card-value {
            font-size: 2rem;
            font-weight: bold;
            color: var(--primary-color);
        }

        .footer {
            display: flex;
            justify-content: center;
            gap: var(--spacing);
            margin-top: var(--spacing);
            padding-top: var(--spacing);
            border-top: 1px solid #ddd;
        }

        @media print {
            .card-container {
                grid-template-columns: repeat(2, 1fr);
            }
        }
    </style>
</head>
<body>
    <div class='header'>
        <h1>Dashboard Report</h1>
        <span>Q4 2025</span>
    </div>

    <div class='card-container'>
        <div class='card'>
            <div class='card-header'>
                <span>Revenue</span>
                <span>+12%</span>
            </div>
            <div class='card-value'>$2.4M</div>
        </div>
        <div class='card'>
            <div class='card-header'>
                <span>Users</span>
                <span>+8%</span>
            </div>
            <div class='card-value'>48.2K</div>
        </div>
        <div class='card'>
            <div class='card-header'>
                <span>Orders</span>
                <span>+15%</span>
            </div>
            <div class='card-value'>12.8K</div>
        </div>
    </div>

    <div class='footer'>
        <span>Generated: " + DateTime.Now.ToString("yyyy-MM-dd") + @"</span>
    </div>
</body>
</html>";

        using var pdf = renderer.RenderHtmlAsPdf(html);
        return pdf.BinaryData;
    }
}
Enter fullscreen mode Exit fullscreen mode

Key points:

  • CSS Variables work (--primary-color, --spacing)
  • Flexbox layouts render correctly
  • CSS Grid creates responsive columns
  • @media print query is respected

Code Example: CSS Grid Layout

public byte[] GenerateGridReport()
{
    var renderer = new ChromePdfRenderer();

    string html = @"
<!DOCTYPE html>
<html>
<head>
    <style>
        body {
            font-family: 'Segoe UI', sans-serif;
            margin: 0;
            padding: 20px;
        }

        .report-grid {
            display: grid;
            grid-template-columns: 1fr 2fr;
            grid-template-rows: auto 1fr auto;
            gap: 20px;
            min-height: 100vh;
        }

        .header {
            grid-column: 1 / -1;
            background: linear-gradient(135deg, #1e3c72, #2a5298);
            color: white;
            padding: 30px;
            border-radius: 8px;
        }

        .sidebar {
            background: #f8f9fa;
            padding: 20px;
            border-radius: 8px;
        }

        .main-content {
            background: white;
            padding: 20px;
            border: 1px solid #e9ecef;
            border-radius: 8px;
        }

        .footer {
            grid-column: 1 / -1;
            text-align: center;
            padding: 15px;
            background: #343a40;
            color: white;
            border-radius: 8px;
        }

        .stat-grid {
            display: grid;
            grid-template-columns: repeat(2, 1fr);
            gap: 15px;
        }

        .stat-card {
            padding: 15px;
            background: white;
            border-radius: 4px;
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
        }
    </style>
</head>
<body>
    <div class='report-grid'>
        <div class='header'>
            <h1>Annual Report 2025</h1>
            <p>Financial Overview and Performance Metrics</p>
        </div>

        <div class='sidebar'>
            <h3>Quick Stats</h3>
            <div class='stat-grid'>
                <div class='stat-card'>
                    <div>Revenue</div>
                    <strong>$12.4M</strong>
                </div>
                <div class='stat-card'>
                    <div>Growth</div>
                    <strong>+23%</strong>
                </div>
                <div class='stat-card'>
                    <div>Customers</div>
                    <strong>8,432</strong>
                </div>
                <div class='stat-card'>
                    <div>NPS Score</div>
                    <strong>72</strong>
                </div>
            </div>
        </div>

        <div class='main-content'>
            <h2>Executive Summary</h2>
            <p>This year demonstrated strong performance across all key metrics...</p>
        </div>

        <div class='footer'>
            <p>Generated: " + DateTime.Now.ToString("MMMM dd, yyyy") + @"</p>
        </div>
    </div>
</body>
</html>";

    using var pdf = renderer.RenderHtmlAsPdf(html);
    return pdf.BinaryData;
}
Enter fullscreen mode Exit fullscreen mode

Code Example: Flexbox Navigation and Card Layout

public byte[] GenerateFlexboxDocument()
{
    var renderer = new ChromePdfRenderer();

    string html = @"
<!DOCTYPE html>
<html>
<head>
    <style>
        * { box-sizing: border-box; margin: 0; padding: 0; }

        .navbar {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 15px 30px;
            background: #2c3e50;
            color: white;
        }

        .nav-links {
            display: flex;
            gap: 25px;
            list-style: none;
        }

        .content {
            padding: 30px;
        }

        .card-row {
            display: flex;
            gap: 20px;
            margin-bottom: 20px;
        }

        .card {
            flex: 1;
            padding: 20px;
            background: #f8f9fa;
            border-radius: 8px;
            display: flex;
            flex-direction: column;
        }

        .card-title {
            font-weight: bold;
            margin-bottom: 10px;
        }

        .card-content {
            flex: 1;
        }

        .card-footer {
            margin-top: auto;
            padding-top: 15px;
            border-top: 1px solid #dee2e6;
        }
    </style>
</head>
<body>
    <nav class='navbar'>
        <div class='logo'>Company Name</div>
        <ul class='nav-links'>
            <li>Dashboard</li>
            <li>Reports</li>
            <li>Settings</li>
        </ul>
    </nav>

    <div class='content'>
        <div class='card-row'>
            <div class='card'>
                <div class='card-title'>Sales</div>
                <div class='card-content'>Monthly sales figures and trends.</div>
                <div class='card-footer'>Updated: Today</div>
            </div>
            <div class='card'>
                <div class='card-title'>Inventory</div>
                <div class='card-content'>Current stock levels and alerts.</div>
                <div class='card-footer'>Updated: Today</div>
            </div>
            <div class='card'>
                <div class='card-title'>Orders</div>
                <div class='card-content'>Pending and completed orders.</div>
                <div class='card-footer'>Updated: Today</div>
            </div>
        </div>
    </div>
</body>
</html>";

    using var pdf = renderer.RenderHtmlAsPdf(html);
    return pdf.BinaryData;
}
Enter fullscreen mode Exit fullscreen mode

API Reference

For CSS support details:

Migration Considerations

Licensing

  • iText pdfHTML is a commercial add-on
  • IronPDF is commercial software with perpetual licensing
  • IronPDF Licensing

API Differences

  • iText: HtmlConverter.ConvertToPdf()
  • IronPDF: ChromePdfRenderer.RenderHtmlAsPdf()
  • HTML templates typically work unchanged with IronPDF

What You Gain

  • Complete CSS3 support (Flexbox, Grid, Variables)
  • Same templates work for web and PDF
  • No need for fallback layouts

What to Consider

  • Different library, different API
  • Chromium-based rendering
  • Commercial licensing for both options

Conclusion

iText pdfHTML's limited CSS support forces developers to choose between modern web layouts and PDF generation. Maintaining separate templates doubles effort and introduces inconsistency. For projects where HTML templates need to render identically in browsers and PDFs, Chromium-based rendering provides the CSS compatibility that custom rendering engines cannot match.


Written by Jacob Mellor, who leads technical development at Iron Software.


References

  1. iText pdfHTML Documentation{:rel="nofollow"} - CSS limitations noted

For the latest IronPDF documentation and tutorials, visit ironpdf.com.

Top comments (0)