skip to Main Content

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

2

Answers


  1. Chosen as BEST ANSWER

    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>
    

  2. 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;
        }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search