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:
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:
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
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."
improve your css