Topics

¡Los certificados e informes del servicio de diagnóstico de accesibilidad ahora están disponibles en PDF!

  • column

El servicio de diagnóstico de accesibilidad de Liberogic ofrecía certificados e informes en formato HTML. Atendiendo a las peticiones de quienes nos pedían un certificado en PDF, ahora podemos emitir certificados e informes en formato PDF!

Certificado de verificación de accesibilidad web en PDF

Informe de conformidad de accesibilidad en PDF (VPAT / ACR)

Para esta mejora, construimos un sistema que genera automáticamente un PDF al mismo tiempo que se exporta el HTML durante el proceso de compilación.

🛠️ Base para la generación de PDF: Puppeteer y configuración del entorno

Como herramienta de generación de PDF, elegimos Puppeteer, que permite controlar el navegador Chromium en modo headless. Dado que el HTML ya estaba construido con Astro, la integración de Puppeteer fue relativamente sencilla.

1. Configuración de un entorno de renderizado con servidor local

Puppeteer utiliza la función de impresión de Chromium, pero al cargar directamente un archivo HTML local (file://), el diseño se rompe.

To work around this, we set up the following environment.

  • Temporary web server: After the build, a temporary local web server (http-server) that hosts the dist directory is launched as a Node.js child process.
  • Stable environment: By having Puppeteer access the site through the server (http://localhost:8080), we ensured a stable rendering environment identical to the browser's.

Excerpt of the code for setting up the environment and starting the server

// プロジェクト定数からドメインを取得し、未設定なら 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. Applying Japanese fonts

The local server environment used for PDF generation does not include Japanese fonts, which causes the fonts embedded in the PDF to be garbled.

  • Font workaround: Immediately before PDF generation, the script dynamically inserts a web font reference and the applicable styles into the DOM. This makes it possible to output PDFs with Japanese fonts. Because the HTML side uses no web fonts in order to prioritize speed, this dynamic insertion ensures the font is applied only to the PDF.

Excerpt of the code for dynamically inserting fonts

// 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);

🚨 Biggest challenge: Link URL reference issue inside the PDF

The most difficult part was the links between PDFs. Links embedded in the PDF kept referencing the local development URL (http://localhost:8080) even after deployment. This happens because Chromium retains the base URI from when it loaded the HTML as the basis for the PDF links.

Forzar rutas absolutas en los enlaces

Para resolverlo, reescribimos los enlaces mediante el siguiente procedimiento, forzándolos a rutas absolutas completas una vez desplegado el sitio.

  1. Uso del dominio de despliegue: Se obtiene el dominio de despliegue (por ejemplo, https://example.com) a partir de la constante del proyecto SITE_URL.
  2. Construcción y sustitución de URLs absolutas: Con Node.js se obtiene el contenido HTML y se reemplaza el enlace original (/accessibility_report/top/) por una URL completa basada en el dominio obtenido (por ejemplo, https://example.com/accessibility_report/pdf/acr-top.pdf).
  3. Reaplicación en el DOM: Al volver a cargar el HTML reescrito en Chromium mediante page.setContent(), se fijaron de forma fiable los enlaces incrustados en el PDF al dominio de despliegue previsto.

Código de reescritura de enlaces (extracto)

// 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
});

🎉 Resumen

Como este caso requería enlazar entre archivos PDF, nos costó un poco, pero la integración de Puppeteer fue bastante sencilla. La compilación también es rápida, y nos pareció una herramienta muy útil.

Los puntos clave de esta solución son los siguientes:

  • Estabilidad garantizada mediante renderizado a través de un servidor local
  • Soporte para japonés mediante la inserción dinámica de fuentes web
  • Enlaces entre PDF mediante la conversión de rutas relativas a absolutas

Con la compatibilidad con PDF, la comodidad de nuestro servicio ha mejorado notablemente. Seguiremos buscando la calidad de nuestro servicio de diagnóstico de accesibilidad para ofrecer un valor real a nuestros clientes.

Autor de este artículo

Pasó del DTP al mundo web y, sin darse cuenta, domina el maquetado, el frontend, la dirección de proyectos y la accesibilidad: un auténtico "maestro de todas las técnicas". Desde los inicios de Liberogic ha desempeñado múltiples funciones y hoy es una auténtica enciclopedia viviente dentro de la empresa. Últimamente se ha obsesionado con la optimización mediante prompts, preguntándose: «¿No podríamos apoyarnos más en la IA para la accesibilidad?». Su tecnología y su forma de pensar siguen evolucionando.

Ayumu Futamata

Especialista en Accesibilidad Web certificado por IAAP (WAS) / Ingeniero de marcado / Ingeniero frontend / Director web

Ver los artículos de este miembro del equipo

Casos de Estudio