De dienst voor toegankelijkheidsdiagnostiek van Liberogic leverde certificaten en rapporten voorheen in HTML-indeling, maar naar aanleiding van verzoeken om PDF-certificaten kunnen we nu certificaten en rapporten in PDF-indeling uitgeven!
PDF-certificaat voor webtoegangsonderzoek
PDF-conformiteitsrapport voor toegankelijkheid (VPAT / ACR)
Voor deze implementatie hebben we een systeem gebouwd dat tegelijkertijd met de HTML-uitvoer in het buildproces ook automatisch PDF genereert.
🛠️ PDF-conversie-basis: Puppeteer en omgevingsconfiguratie
We hebben Puppeteer gekozen als PDF-generatietool, waarmee we de Chromium-browser headless kunnen aansturen. Omdat de HTML al met Astro is gebouwd, verliep de implementatie van Puppeteer relatief soepel.
1. Renderingomgeving met lokale server
Puppeteer gebruikt de afdrukfunctie van Chromium, maar wanneer lokale HTML-bestanden (file://) rechtstreeks worden geladen, treedt een layoutproblem op.
Om dit te voorkomen, hebben we de volgende omgeving opgezet.
- Tijdelijke webserver: Na het bouwen wordt de
dist-directory gehost door een tijdelijke lokale webserver (http-server), gelanceerd als een onderproces van Node.js. - Stabiele omgeving: Door Puppeteer via de server (
http://localhost:8080) toegang te geven, zorgden we voor een stabiele renderingomgeving die gelijk is aan die van de browser.
Code voor omgevingsconfiguratie en serverstartup (fragment)
// プロジェクト定数からドメインを取得し、未設定なら localhost:8080 を使用
const HOST_DOMAIN = SITE_URL || `http://localhost:${PORT}`;
const BUILD_ROOT = path.join(__dirname, 'dist');
const PORT = 8080;
// --- サーバーの起動ロジック ---
let serverProcess = exec(`npx http-server ${BUILD_ROOT} -p ${PORT} -s --silent`);
// サーバーが起動するまで待機
await new Promise((resolve) => setTimeout(resolve, 2000));
// --- Puppeteerのページアクセス ---
// Puppeteerは localhost:8080 にアクセスし、レンダリングを開始します
const serverUrl = `http://localhost:${PORT}/${REPORT_DIR}/${urlPath}`;
await page.goto(serverUrl, { waitUntil: 'networkidle0' });
2. Toepassing van Japanse lettertypen
De lokale serveromgeving voor PDF-generatie heeft geen Japanse lettertypen, wat leidt tot problemen met onjuiste lettertypen in de gegenereerde PDF.
- Workaround voor lettertypen: In het script worden webfontverwijzingen en toegepaste stijlen dynamisch in de DOM ingevoegd voordat de PDF wordt gegenereerd. Dit maakt PDF-uitvoer met Japanse lettertypen mogelijk. Omdat de HTML-kant snelheid prioriteert en geen webfonts gebruikt, zorgt deze dynamische injectie ervoor dat lettertypen alleen voor de PDF worden toegepast.
Code voor dynamische fontinjectie (fragment)
// Webフォントの動的挿入ロジック (page.evaluateでブラウザ側で実行)
await page.evaluate((fontUrl) => {
// <link>タグを生成してDOMに挿入
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = fontUrl;
document.head.appendChild(link);
// @media print スタイルを強制的に挿入し、フォントを適用
const printStyle = document.createElement('style');
printStyle.textContent = `
@media print {
html, body {
font-family: 'Noto Sans JP', sans-serif !important;
}
}
`;
document.head.appendChild(printStyle);
}, WEBFONTS_URL);
🚨 Grootste uitdaging: URL-referentie van koppelingen in PDF
Het meest lastige waren de koppelingen tussen PDF's. Koppelingen in de PDF bleven verwijzen naar de URL van de lokale ontwikkelomgeving (http://localhost:8080) zelfs na implementatie. Dit gebeurt omdat Chromium de basis-URI van het geladen HTML behoudt als het basispunt voor PDF-koppelingen.
Links naar absolute paden forceren
Om dit op te lossen, hebben we links in de volgende stappen geforceerd herschreven naar volledige absolute paden na implementatie.
- Het domein van de implementatieplek gebruiken: Het domein van de implementatieplek (bijvoorbeeld
https://example.com) wordt opgehaald uit de projectconstante (SITE_URL). - Absolute URL's samenstellen en vervangen: Met Node.js wordt de HTML-inhoud opgehaald en wordt de originele link (
/accessibility_report/top/) herschreven naar een volledige URL (bijvoorbeeldhttps://example.com/accessibility_report/pdf/acr-top.pdf) op basis van het opgehaalde domein. - Opnieuw toepassen op de DOM: Door de herschreven HTML opnieuw toe te passen op Chromium (
page.setContent()), worden de links in de PDF vastgesteld op het beoogde implementatiedomein.
Code voor linksherschrijving (uittreksel)
// 1. 無効化したいリンク(.link-ignore-pdf)を物理的に削除
const ignoreLinkRegex = new RegExp(`(<a\\\\s+[^>]*class=["'][^"']*${ignoreClass}[^"']*["'][^>]*>)(.*?)(<\\/a\\\\s*>)`, 'gi');
content = content.replace(ignoreLinkRegex, '$2'); // <a>タグ全体を中身のテキストに置換
// 2. 詳細ページへのリンクを絶対URLに書き換え
const detailLinkRegex = new RegExp(`href="${reportDirRootLink}([^/]+)\\/"`, 'g');
const detailPdfUrl = `${pdfAbsoluteUrl}/acr-top.pdf`; // 例
content = content.replace(detailLinkRegex, (match, slug) => {
// リンクを <http://localhost>... ではなく、<https://example.com/>... に強制置換
return `href="${pdfAbsoluteUrl}/acr-${slug}.pdf"`;
});
// 3. 最終的なコンテンツをブラウザに再適用し、PDF出力へ
await page.setContent(content, {
waitUntil: 'domcontentloaded',
baseURL: baseUrlForContent
});
🎉 Samenvatting
Deze keer hadden we te maken met een enigszins bijzondere vereiste: het maken van links tussen PDF's. Dit gaf ons wat kopzorgen, maar de implementatie van Puppeteer zelf verliep vrij soepel. De build is snel en het is een erg handig hulpmiddel!
De belangrijkste punten van deze aanpak zijn als volgt:
- Stabiliteit waarborgen door rendering via lokale server
- Dynamische webfont-injectie voor Japanse taalondersteuning
- Absolute paden voor links tussen PDF's
Met PDF-ondersteuning is de bruikbaarheid van onze diensten aanzienlijk verbeterd. We zullen blijven streven naar het leveren van waardevolle accessibility-diagnostische diensten van hoge kwaliteit voor onze klanten!
Vanuit DTP de wereld van het web in gestapt en merkte al snel dat hij markering, frontend, directie en accessibility allemaal beheerst — een echte 'meester van techniek'. Sinds de oprichting van Liberogic een multitalent en inmiddels een levend naslagwerk in het bedrijf. Tegenwoordig is hij geïnteresseerd in de vraag "Kunnen we accessibility-implementatie meer aan AI overlaten?" en experimenteert hij graag met efficiëntie via prompts. Zowel technisch als mentaal nog volop in ontwikkeling.
Futa
IAAP-gecertificeerd webtoegankelijkheidsspecialist (WAS) / Opmaakingenieur / Frontend-ingenieur / Webdirecteur