Ir al contenido

Maquetar una tabla HTML

Esta receta renderiza una tabla HTML con encabezado, celdas alineadas, bordes y una fila de pie. Las tablas son un módulo marcado como Verificado en la matriz de compatibilidad de CSS. La receta se basa en examples/09-html-table.php.

Ventana de terminal
composer require nextpdf/core:^3

Esta restricción apunta al paquete nextpdf/core. El ejemplo se ejecuta con PHP 8.4.

El motor HTML tiene una canalización dedicada para tablas (src/Html/Table/). TableParser recopila filas y celdas en un búfer efímero; después, la tabla se maqueta y se pinta. Esta es la única desviación reconocida respecto del modelo del ADR-001, que no conserva un DOM. El búfer es efímero y está acotado a su contenedor. No es un DOM persistente.

Los anchos de columna siguen el modelo de tablas CSS. La tabla se maqueta con un ancho usado determinado y, luego, el algoritmo de dimensionamiento de columnas fija el ancho usado de cada columna (W3C CSS Table Level 3). Con table-layout: fixed, el contenido de las celdas se ignora para el cálculo del ancho. En su lugar, la primera fila y los anchos explícitos de columna guían la maquetación (W3C CSS Table Level 3).

CSS Table Level 3 figura como Verificado en la matriz. Cuatro fuentes respaldan esta calificación: src/Html/Table/, la suite de pruebas unitarias de Table, las pruebas de TableParser y los PDF golden sintéticos.

Las tablas se renderizan mediante writeHtml(string $html): static (NextPDF\Core\Concerns\HasTextOutput). El motor admite el marcado estándar de tablas. Las etiquetas admitidas son table, thead, tbody, tfoot, tr, th y td. Los atributos admitidos son border, cellpadding, cellspacing, colspan y un style por celda. La tabla completa de PHPDoc se genera a partir del código fuente.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->addPage();
$doc->writeHtml(
'<table border="1" cellpadding="5"><tr><th>SKU</th><th>Qty</th></tr>'
. '<tr><td>NPD-CORE</td><td style="text-align: right;">1</td></tr></table>'
);
$doc->save(__DIR__ . '/out.pdf');

Este ejemplo es autónomo y el harness puede ejecutarlo. Corresponde a examples/09-html-table.php y muestra un encabezado con estilo, fondos alternos en las filas, columnas numéricas alineadas y un total en el pie.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('HTML Table');
$doc->addPage();
$html = <<<'HTML'
<h1 style="color: #1E3A8A;">Product Inventory Report</h1>
<table border="1" cellpadding="5" cellspacing="0" style="width: 100%;">
<thead>
<tr style="background-color: #1E3A8A; color: #FFFFFF;">
<th style="width: 10%;">#</th>
<th style="width: 45%;">Product</th>
<th style="width: 20%; text-align: center;">SKU</th>
<th style="width: 25%; text-align: right;">Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>NextPDF Core License</td>
<td style="text-align: center;">NPD-CORE</td>
<td style="text-align: right;">$0.00</td>
</tr>
<tr style="background-color: #F8FAFC;">
<td>2</td>
<td>NextPDF Pro License</td>
<td style="text-align: center;">NPD-PRO</td>
<td style="text-align: right;">$299.00</td>
</tr>
</tbody>
<tfoot>
<tr style="background-color: #1E293B; color: #FFFFFF; font-weight: bold;">
<td colspan="3" style="text-align: right;">Grand total:</td>
<td style="text-align: right;">$299.00</td>
</tr>
</tfoot>
</table>
HTML;
$doc->writeHtml($html);
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');
$doc->save($out !== false ? $out : __DIR__ . '/html-table-layout.pdf');
echo "Wrote html-table-layout.pdf\n";

STDOUT esperado:

Wrote html-table-layout.pdf
  • Anchos en porcentaje. Los porcentajes de width de columna se resuelven con respecto al ancho usado de la tabla. El algoritmo de dimensionamiento de columnas normaliza los porcentajes que no suman 100. No asumir anchos exactos en píxeles.
  • colspan. Una celda que abarca varias columnas participa en la distribución de anchos entre las columnas que cubre. Un total en el pie que abarca la mayoría de las columnas es un patrón común y admitido.
  • Modelo de bordes. En algunas fixtures de tablas, el valor predeterminado de border-collapse difiere del valor inicial de CSS. Definirlo explícitamente cuando el renderizado de los bordes sea importante.
  • Rowspan a través de saltos de página. Una celda con rowspan puede cruzar un límite de página; en ese caso, el paginador de rowspan fragmenta esa celda (ADR-007). Una celda muy alta que no se puede dividir puede lanzar UnsplittableContentException.
  • Celdas vacías. Un <td> vacío sigue ocupando su casilla en la cuadrícula. No se colapsa ni se elimina.

El búfer de la tabla es efímero y está acotado a su contenedor. Los costos de análisis son lineales con respecto al número de celdas, más una pasada de dimensionamiento de columnas en O(filas x columnas). El presupuesto es wall_ms: 1500, peak_mb: 96. Mantener una sola tabla dentro del límite de nodos del ADR-020 de 5,000 nodos por contexto.

Extracto de la matriz de compatibilidad de CSS (solo filas con Verificado)

Sección titulada «Extracto de la matriz de compatibilidad de CSS (solo filas con Verificado)»

Este extracto reproduce únicamente las filas Verificado de la matriz de compatibilidad de CSS auditada con criterios de veracidad.

Módulo de la W3CNivelEstadoEvidencia
CSS Table (css_tables_3)3Verificadosrc/Html/Table/, tests/Unit/Html/Table/ + pruebas de TableParser + PDF golden
CSS Flexible Box Layout (css_flexbox_1)1Verificadosrc/Html/Flex/, tests/Unit/Html/Flex/
CSS Grid Layout (css_grid_1)1Verificadosrc/Html/Grid/, corpus WPT
CSS Cascading and Inheritance (css_cascade_3)3Verificadosrc/Html/Cascade/

background-color, usado aquí para el rayado de filas, está calificado como «Claimed» en la matriz. Según la auditoría de la Fase 0, su alcance es la celda de la tabla. Se renderiza para las filas de la tabla, pero no figura como Verificado.

Restricciones del streaming en una sola pasada (ADR-001)

Sección titulada «Restricciones del streaming en una sola pasada (ADR-001)»

El búfer de la tabla es la excepción documentada al modelo de streaming. Es efímero y acotado, no un DOM general. No depender de una tabla para aportar contexto de árbol a contenido que esté fuera de la tabla.

FormattingContextFactory::startTable() lee el CSS a través del contrato de la capa de maquetación. No analiza $css[...] en bruto en el dispatch. La superficie pública sigue siendo writeHtml().

Presupuesto de memoria para documentos grandes

Sección titulada «Presupuesto de memoria para documentos grandes»

Un contexto de formato de tabla está acotado a 5,000 nodos y 20 niveles de profundidad, dentro del techo de memoria activa de 50 MB (ADR-020). Dividir o paginar una tabla muy grande. No renderizarla como un único contexto sobredimensionado.

El marcado de tablas procedente de entradas no confiables está acotado por los mismos límites de elementos y de anidamiento que el resto del HTML. Validar los datos de tabla que un usuario construya. El renderer no ejecuta el contenido y, bajo la política predeterminada, no obtiene recursos remotos arbitrarios.

DeclaraciónEspecificaciónCláusulareference_id
El algoritmo de dimensionamiento de columnas de la tabla determina los anchos de columna usados al ancho usado de la tabla.W3C CSS Table Level 3css_tables_3#x1.x4.x9.x3
En modo fixed, el contenido de las celdas se ignora para el cálculo del ancho de columna.W3C CSS Table Level 3css_tables_3#x1.x4.x5.x1.p6

Esta receta muestra cómo NextPDF renderiza las tablas HTML admitidas. CSS Table Level 3 figura como Verificado en la matriz de compatibilidad, y los demás módulos de CSS usados aquí se califican conforme a esa matriz.

No aplica.