0

I'm using spatie/browsershot to generate pdf documents in a laravel project. It has built in headerHtml and footerHtml methods but it is buggy with images, first it only accepts base64/svg and some images with transparent background are getting truncated when printed.

So I use CSS instead to insert my header and footer. But the problem occurs when I put @page margin, because my header and footer are getting pushed back by the margin. As shown below: Header getting pushed back by @page margin

Note that I have to use @page margin on every page instead of putting margin-top/bottom on the h1-h6 tags since I'm dealing with dynamic content and I don't know when will the pagebreak occur or when will a new page start/end.

Without @page margin, the header and footer is being positioned correctly but the content will loss it's margin and will occupy the page header position like below:

Without @page margin

Index blade file:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Grant Proposal</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        @media print {
            body {
                -webkit-print-color-adjust: exact !important;
                /* Chrome, Safari 6 – 15.3, Edge */
                color-adjust: exact !important;
                /* Firefox 48 – 96 */
                print-color-adjust: exact !important;
                /* Firefox 97+, Safari 15.4+ */
            }

            div.paper[data-size="A4"] {
                margin: 0;
                box-shadow: 0;
                -webkit-column-break-inside: avoid;
                page-break-inside: avoid;
                break-inside: avoid;
            }

            div.pagebreak {
                break-after: page;
            }

            @page {
                margin-top: 3.54cm;
                margin-bottom: 2.54cm;
            }

            header {
                position: fixed;
                top: 0;
                left: 50%;
                transform: translate(-50%, 0);
                outline: 1px solid red;
            }

            footer {
                position: fixed;
                bottom: 0;
                left: 50%;
                transform: translate(-50%, 0);
                outline: 1px solid red;
            }
        }
    </style>
</head>

<body>
    <header
        style="opacity: 0.6; color: #672F09; width: 12cm; height: 3.54cm; font-size: 16px; margin: 0 auto; display: flex; justify-content: space-between; align-items: center;">
        <div style="width: 75px; height: 75px;">
            <img style="object-fit: contain; height: 100%; width: 100%;"
                src="{{ public_path('/pdo-logos/1632470799-PDO no bg.png') }}" alt="Logo">
        </div>
        <p style="text-align: center; font-weight: 500; width: 70%;">Proposal Title</p>
        <div style="width: 75px; height: 75px;"></div>
    </header>
    {{ $slot }}//content goes here
    <footer
        style="opacity: 0.6; display: flex; justify-content: space-between; align-items: center; width: 12cm; height: 2.54cm; font-size: 12px; margin: 0 auto;">
        <div style="text-align: left; max-width: 60%;">
            <p style="margin-bottom: 0;">Proposal Title</p>
            <p style="margin-top: 0">Series of {{ date('Y') }}</p>
        </div>
        <p><span style="font-weight: 700;">World</span>Front</p>
    </footer>
</body>

</html>

Generate pdf with browsershot

            $html = view('grantproposals.index', ['grant_proposal' => $grant_proposal])->render();

            Browsershot::html($html)
                ->format('A4')
                ->waitUntilNetworkIdle()
                ->newHeadless()
                ->timeout(120)
                ->save($temp_path . 'filename.pdf');

Please advice on how I can fix this? thank you

lance2k
  • 357
  • 1
  • 4
  • 14

2 Answers2

0

improve your css

 header {
        position: fixed;
        top: 0;
        left: 0;
        width: 100%; 
        padding: 20px; 
        box-sizing: border-box; 
        background-color: #ffffff; 
        opacity: 0.6;
        text-align: center; 
        color: #672F09;
        font-size: 16px;
    }

footer {
        position: fixed;
        bottom: 0;
        left: 0;
        width: 100%; 
        padding: 10px; 
        box-sizing: border-box; 
        background-color: #ffffff; 
        opacity: 0.6;
        text-align: center;
        font-size: 12px;
    }
Akshay ak
  • 63
  • 4
0

I was able to fix this using the table hack from this blog post: https://medium.com/@Idan_Co/the-ultimate-print-html-template-with-header-footer-568f415f6d2a

"The concept is to use the table method to create empty “place-holders” that will prevent the content from overlapping the header/footer. We’re keeping it empty so that on the last page nothing will be shown. Then, we can use the fixed-position method to place the actual header/footer inside the empty place-holders."

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Grant Proposal</title>

    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        @media print {
            body {
                -webkit-print-color-adjust: exact !important;
                /* Chrome, Safari 6 – 15.3, Edge */
                color-adjust: exact !important;
                /* Firefox 48 – 96 */
                print-color-adjust: exact !important;
                /* Firefox 97+, Safari 15.4+ */
            }

            div.paper[data-size="A4"] {
                margin: 0;
                box-shadow: 0;
                -webkit-column-break-inside: avoid;
                page-break-inside: avoid;
                break-inside: avoid;
            }

            div.pagebreak {
                break-after: page;
            }

            header,
            .header-space {
                height: 3.54cm;
            }

            footer,
            .footer-space {
                height: 2.54cm;
            }

            header {
                position: fixed;
                top: 0;
                left: 50%;
                transform: translate(-50%, 0);
                opacity: 0.6;
                color: #672f09;
                width: 16cm;
                font-size: 16px;
                margin: 0 auto;
                display: flex;
                justify-content: space-between;
                align-items: center;
            }

            footer {
                position: fixed;
                bottom: 0;
                left: 50%;
                transform: translate(-50%, 0);
                opacity: 0.6;
                display: flex;
                justify-content: space-between;
                align-items: center;
                width: 16cm;
                font-size: 12px;
                margin: 0 auto;
            }
        }
    </style>

</head>

<body>

    <table>
        <thead>
            <tr>
                <td>
                    <div class="header-space">&nbsp;</div>
                </td>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>{{ $slot }}</td>
            </tr>
        </tbody>
        <tfoot>
            <tr>
                <td>
                    <div class="footer-space">&nbsp;</div>
                </td>
            </tr>
        </tfoot>
    </table>

    <header>
        {{ $heading }}
    </header>
    <footer>
        {{ $footer }}
    </footer>

</body>
</html>
lance2k
  • 357
  • 1
  • 4
  • 14