Save styling in dompdf while pagination -- include Bootstrap

In coeigniter 3 I have following method to create html content for dompdf based on data fetched from a SQL table which already created by ckeditor on my web portal:

public function generatePageHtml($report_name, $title1, $title2 = null, $title3 = null, $content, $image_path, $cover1_image_path = null, $cover2_image_path = null, $page_number = null) { 
    $cover_base64 = $this->getCoverImageBase64($title2, $cover1_image_path, $cover2_image_path, $image_path);

    $html = '';
    $html .= '<html><body>';
    if ($cover_base64) {
        $html .= '<img src="' . $cover_base64 . '" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; object-fit: cover; margin: 0; padding: 0; opacity: 0.3;">';
    }
    // Load logo image
    $logo_html = $this->generateLogoHtml();
    if ($title2 !== 'Cover 1' && $title2 !== 'Back Cover') {

        if ($logo_html) {
            $html .= $logo_html;
        }
    }    
    $html .= '<div style="position: relative; z-index: 2; padding: 20px;">';
    if ($title2 !== 'Cover 1' && $title2 !== 'Back Cover') {
        $html .= $this->generateTitleHtml($title1, $title2);
    }
    $html .= '<div style="margin: 10px 25px 4px 5px;">'; 
    $html .= '<div>' . $content . '</div>';
    $html .= '</div>'; 
    $html .= '</div>'; 
    if ($title2 !== 'Cover 1' && $title2 !== 'Back Cover') {
        $html .= '<div style="position: absolute; bottom: 20px; left: 20px; font-size: 12px; font-weight: bold; font-style: italic; color: black;"> ' 
                    . $report_name .' - '. $title1 .' - '. $title2 . '</div>';
    }
    $html .= '</body></html>'; 
    return $html;
}

In fact, this code is used in a for loop to create html content for dompdf from various SQL table columns aimed to create a compilate report. Here I have 2 main troubles:

1-Sometime the content of each column could exceed one a4 page (landscape); but in the generated pdf, the page margins are not considered for these exceeded pages! So the content in them has no margin while I need to consider same styling overall for the report pdf.

2-Secondly, some HTML content could use the Bootstrap library. e.g. icons or other paragraph styling. So the final generated pdf should be faithful to user content styling while I include this library in the head of the html, but that does not make sense. e.g. the coeditor content has 2 column-styled paragraph. In the generated pdf they are placed as 1 column paragraph.

in attach is an image of what i mean!


in brief bootstrap does not acted as expected in pdf generation even when i include any version or any online or on server source. Do you have any suggestions to deal with these concepts?

To address the challenges you’re facing with generating PDFs using DOMPDF in CodeIgniter 3, let’s analyze and suggest solutions for both issues:


1. Content Overflow Without Margins

When content exceeds one page, DOMPDF often struggles with consistent page styling and margin enforcement.

Solution:

  • Ensure that your CSS explicitly defines margins, padding, and page breaks. Use the following CSS:

css

Copy code

@page {
    margin: 20mm; /* Set uniform margins for the PDF */
}

body {
    margin: 0;
    padding: 0;
}

div {
    page-break-inside: avoid; /* Prevent cutting elements between pages */
}

table {
    page-break-inside: auto;
}
  • Add CSS directly in your $html variable before generating the content:

php

Copy code

$html .= '<style>
              @page { margin: 20mm; }
              body { margin: 0; padding: 0; }
              div { page-break-inside: avoid; }
          </style>';

2. Bootstrap Library and Inconsistent Styling

DOMPDF has limited support for modern CSS, JavaScript, and some external libraries (like Bootstrap). This often results in issues with advanced layouts and components like columns, icons, etc.

Solution:

  1. Flatten Bootstrap Styles for PDF:
  • Bootstrap uses dynamic JavaScript and complex CSS for rendering, which DOMPDF cannot interpret. Use a simplified version of Bootstrap by manually extracting relevant styles and adding them to your HTML.Example:

php

Copy code

$html .= '<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">';
  1. Use DOMPDF-Compatible CSS:
  • Bootstrap components like icons and column layouts might not render properly. Instead, use static CSS that DOMPDF can process.Example of simplified columns:

html

Copy code

<div style="display: flex; justify-content: space-between;">
    <div style="width: 48%;">Column 1 Content</div>
    <div style="width: 48%;">Column 2 Content</div>
</div>
  1. Test Bootstrap Icons: If icons are missing, ensure you embed their corresponding fonts directly:

php

Copy code

$html .= '<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet">';
  1. Use DOMPDF Inline Style Options: DOMPDF prefers inline styles. If you rely heavily on Bootstrap classes, convert them into inline CSS for the PDF.Example: Replace:

html

Copy code

<div class="col-md-6">Content</div>

With:

html

Copy code

<div style="width: 50%; float: left;">Content</div>

Additional Recommendations:

  • Debugging DOMPDF Issues:
    • Enable DOMPDF debug mode to identify unsupported elements:

php

Copy code

$options = new Dompdf\Options();
$options->setDebugCss(true);
$options->setDebugLayout(true);
$dompdf->setOptions($options);
  • Consider wkhtmltopdf for Complex Styling:
    • DOMPDF is lightweight but limited. If PDF fidelity to Bootstrap is critical, switch to a more powerful library like wkhtmltopdf that uses Webkit for rendering. It supports all modern CSS and JavaScript.

Modified generatePageHtml Method:

Here’s an improved version of your method with the solutions applied:

php

Copy code

public function generatePageHtml($report_name, $title1, $title2 = null, $title3 = null, $content, $image_path, $cover1_image_path = null, $cover2_image_path = null, $page_number = null) { 
    $cover_base64 = $this->getCoverImageBase64($title2, $cover1_image_path, $cover2_image_path, $image_path);

    $html = '<html><head>';
    $html .= '<style>
                  @page { margin: 20mm; }
                  body { margin: 0; padding: 0; font-family: Arial, sans-serif; }
                  div { page-break-inside: avoid; }
                  .two-column { display: flex; justify-content: space-between; }
                  .two-column > div { width: 48%; }
              </style>';
    $html .= '</head><body>';
    
    if ($cover_base64) {
        $html .= '<img src="' . $cover_base64 . '" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; object-fit: cover; margin: 0; padding: 0; opacity: 0.3;">';
    }
    $logo_html = $this->generateLogoHtml();
    if ($title2 !== 'Cover 1' && $title2 !== 'Back Cover') {
        if ($logo_html) {
            $html .= $logo_html;
        }
    }    
    $html .= '<div style="position: relative; z-index: 2; padding: 20px;">';
    if ($title2 !== 'Cover 1' && $title2 !== 'Back Cover') {
        $html .= $this->generateTitleHtml($title1, $title2);
    }
    $html .= '<div style="margin: 10px 25px 4px 5px;">'; 
    $html .= '<div>' . $content . '</div>';
    $html .= '</div>'; 
    $html .= '</div>'; 
    if ($title2 !== 'Cover 1' && $title2 !== 'Back Cover') {
        $html .= '<div style="position: absolute; bottom: 20px; left: 20px; font-size: 12px; font-weight: bold; font-style: italic; color: black;"> ' 
                    . $report_name .' - '. $title1 .' - '. $title2 . '</div>';
    }
    $html .= '</body></html>'; 
    return $html;
}

Let me know if you need further assistance!