I am using Browsershot, which is based on Puppeteer to create PDF from HTML. The HTML-source is rendered Laravel-Blade.
This is my blade-template that is being rendered:
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8">
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<meta content="width=device-width,initial-scale=1.0" name="viewport">
<!-- Styles -->
<link href="{{ asset(mix('/css/app.css')) }}" rel="stylesheet">
<body>
<div class="relative h-screen">
@include('pdf.partials.header')
<div class="absolute inset-x-0 bottom-0">
@include('pdf.partials.footer')
</div>
</div>
</body>
</html>
app.css
contains @font-faces
like:
/* lato-100 - latin */
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 100;
src: local('Lato Hairline'), local('Lato-Hairline'),
url('../fonts/lato-v16-latin-100.woff2') format('woff2'), /* Super Modern Browsers */ url('../fonts/lato-v16-latin-100.woff') format('woff'), /* Modern Browsers */ url('../fonts/lato-v16-latin-100.ttf') format('truetype'), /* Safari, Android, iOS */ url('../fonts/lato-v16-latin-100.svg#Lato') format('svg'); /* Legacy iOS */
font-display: swap;
}
/* lato-100italic - latin */
@font-face {
font-family: 'Lato';
font-style: italic;
font-weight: 100;
src: local('Lato Hairline Italic'), local('Lato-HairlineItalic'),
url('../fonts/lato-v16-latin-100italic.woff2') format('woff2'), /* Super Modern Browsers */ url('../fonts/lato-v16-latin-100italic.woff') format('woff'), /* Modern Browsers */ url('../fonts/lato-v16-latin-100italic.ttf') format('truetype'), /* Safari, Android, iOS */ url('../fonts/lato-v16-latin-100italic.svg#Lato') format('svg'); /* Legacy iOS */
font-display: swap;
}
Now if I try to create a pdf, those fonts are not loaded correctly.
If I trace that down using:
$view = view('pdf', compact('data'));
$body_html = $view->render();
$requests = \Spatie\Browsershot\Browsershot::html($body_html)->format('A4')
->margins(8, 22, 8, 22)->showBackground()->addChromiumArguments([
'font-render-hinting' => 'none',
])->waitUntilNetworkIdle()->ignoreHttpsErrors()
->triggeredRequests();
dump($requests);
I see those requests:
4 => array:1 [
"url" => "http://example.test/fonts/lato-v16-latin-300.woff2?98d8cf792834c0bef59c2be99dc3533d"
]
I am able to open this path using my browser and the virtual machine Laravel lives in, is able to do so, too:
root@example:~# http://example.test/fonts/ibm-plex-mono-v5-latin-200.woff2?4b65d6136cfc2097c4a2103960f00a2c
Resolving example.test (example.test)... 127.0.0.1, 127.0.1.1
Connecting to example.test (example.test)|127.0.0.1|:80... connected.
HTTP request sent, awaiting response... 200 OK
But the fonts are still not applied.
Now if I simply use Google fonts like this
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8">
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<meta content="width=device-width,initial-scale=1.0" name="viewport">
<!-- Styles -->
<link href="{{ asset(mix('/css/app.css')) }}" rel="stylesheet">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap" rel="stylesheet"></head>
<body>
<div class="relative h-screen">
@include('pdf.partials.header')
<div class="absolute inset-x-0 bottom-0">
@include('pdf.partials.footer')
</div>
</div>
</body>
</html>
it works just fine.
So what did I do wrong?
We had success using this tool to get the base64 version of the google font we were trying to use locally. Embedding the font as base64 right in the CSS allowed us to get around this issue.