O pipeline de HTML
Spec: CSS Cascade 5, §6.1 CSS Cascade 5 §6.1 Spec: CSS Display 3, §2 CSS Display 3 §2 Evidence: Code-backed
Em resumo
Seção intitulada “Em resumo”O NextPDF renderiza HTML e CSS em PDF dentro do processo PHP: sem navegador, sem subprocesso por padrão. Esta página explica os estágios em camadas pelos quais a conversão passa, o que o motor de CSS realmente cobre e quando delegar a um renderizador de navegador real é a escolha mais honesta.
Por que isso importa
Seção intitulada “Por que isso importa”“HTML para PDF” parece uma única operação. Na prática, envolve uma cascade, um box model, uma etapa de layout e uma etapa de pintura. Cada uma delas é um problema bem especificado, com seus próprios modos de falha. Um motor que as funde em um único procedimento é frágil. Uma alteração no parsing de cores pode deslocar uma caixa, e a única forma de perceber isso é renderizar e observar.
O modelo in-process tem uma vantagem real: nenhum navegador para instalar, nenhum sandbox para operar e nenhum limite de processo para atravessar com marshalling. Mas isso só compensa se a conversão for decomposta de forma limpa o suficiente para testar cada preocupação isoladamente. É a arquitetura que torna “renderizar HTML em PHP” confiável, não apenas possível.
A versão resumida
Seção intitulada “A versão resumida”- A conversão de HTML/CSS é executada in-process via
writeHtml(). O resultado é conteúdo PDF nativo, não uma imagem de uma página. - Ela é single-pass e streaming. O tokenizer produz uma lista de tokens. O parser consome essa lista da esquerda para a direita, e nenhuma árvore DOM completa é retida (ADR-001). Limites rígidos restringem a contagem de elementos e a profundidade de aninhamento.
- O motor é organizado em camadas explícitas: parsing de CSS e applicators, estado de estilo, layout e formatação, pintura e paged media — com regras rígidas sobre o que cada camada pode fazer (ADR-010).
- O motor de CSS cobre a cascade, o box model e layouts comuns (block, inline, tabelas, floats e outros) — substancial, mas um subconjunto definido daquilo que um navegador moderno implementa.
- Quando você precisa de fidelidade exata de navegador para CSS moderno arbitrário, o NextPDF pode delegar a um renderizador de navegador headless por meio de uma extensão opcional — um ponto de junção deliberado e isolado da rede, não o caminho padrão.
Como o NextPDF aborda isso
Seção intitulada “Como o NextPDF aborda isso”A conversão é uma sequência de estágios, cada um consumindo a saída tipada do estágio anterior.
- Tokenize HTML becomes an ordered token list — no retained DOM tree.
- Resolve CSS Parse styles; the cascade and applicators compute typed values.
- Style state A push/pop style stack carries computed values per nesting level.
- Layout Block, inline, table, and float geometry computed; no paint here.
- Paint Borders, backgrounds, text, and decorations emit PDF operators.
- Paged media Page-break and @page rules applied as the cursor crosses page bounds.
Duas regras arquiteturais fazem disso mais do que um fluxo.
As camadas têm contratos. O texto de CSS é lido apenas dentro das classes applicator. O código de layout calcula a geometria, mas não emite operadores de pintura. O código de pintura lê um snapshot imutável do estilo computado, nunca o estado mutável de rastreamento de layout. O código de paged media dispara quebras, mas delega a decoração de página à camada de pintura. Esses limites são impostos (ADR-010). É por isso que uma nova propriedade CSS entra como um novo applicator, em vez de uma alteração que se espalha simultaneamente pelo parser, pelo dispatch de layout e pelo painter.
Não há DOM. O pipeline é single-pass e streaming por decisão (ADR-001): no máximo um estado de estilo por nível de aninhamento, mais o cursor ativo, não um objeto por elemento. Algumas operações realmente precisam de look-ahead — dimensionamento de colunas de tabela, :has(), :last-child. Elas são tratadas por estruturas limitadas de índice de pré-varredura sobre a lista plana de tokens, não pela retenção de uma árvore. A contagem de elementos e a profundidade de aninhamento têm limites rígidos, de modo que uma entrada patológica falha rapidamente em vez de esgotar a memória.
O motor de CSS resolve a semântica real do CSS, não uma imitação. Declarações concorrentes são reduzidas a um valor por propriedade por origem, importância, camada, especificidade e ordem — a cascade de fato. O layout segue o box model. O tipo de uma caixa e o formatting context que ela estabelece determinam como ela e seus elementos irmãos in-flow são posicionados. O código-fonte do motor é organizado exatamente em torno dessas preocupações (cascade, box/display, flex, float, tabelas, fragmentação). É por isso que você pode raciocinar sobre o comportamento dele com base nas especificações, em vez de descobri-lo empiricamente.
O que as evidências dizem
Seção intitulada “O que as evidências dizem”Esta página é Evidence: Code-backed . Os estágios e regras correspondem ao repositório core:
- O ponto de entrada in-process é
writeHtml(string $html): staticemsrc/Core/Concerns/HasTextOutput.php. - O design single-pass, sem DOM retido e com limites de elementos e de aninhamento, é descrito pelo ADR-001 e pelo código de tokenizer/parser/style-stack em
src/Html/. - O contrato do motor em camadas — parsing/applicators de CSS, estado de estilo, layout, pintura, paged media — é descrito pelo ADR-010 e refletido na estrutura de
src/Html/(por exemploCascade/,Css/,Flex/,Float/,Fragmentation/e as classes applicator). - O ponto de junção de delegação ao navegador é
writeHtmlChrome()no mesmo arquivo, documentado como exigindo a extensão de renderizador opcional, além de um binário Chrome/Chromium.
Os padrões dão base a uma afirmação honesta de cobertura. A cascade reduz declarações concorrentes a um único valor por propriedade — origem, importância, camada, especificidade, ordem — conforme Spec: CSS Cascade 5, §6.1 CSS Cascade 5 §6.1 , e o posicionamento in-flow segue as regras de box e de formatting context conforme Spec: CSS Display 3, §2 CSS Display 3 §2 . Igualmente importante é o limite: uma feature query existe justamente porque nem todo processador suporta todos os recursos, conforme Spec: CSS Conditional 5, §2 CSS Conditional 5 §2 . O motor de CSS do NextPDF é um subconjunto definido e alinhado às especificações, e afirmar isso claramente faz parte do contrato.
Exemplo prático
Seção intitulada “Exemplo prático”A renderização in-process é uma única chamada. A saída é texto PDF selecionável, não uma página rasterizada:
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('HTML Basic');$doc->addPage();
$html = <<<'HTML'<h1 style="color: #1E3A8A;">HTML Rendering in NextPDF</h1><p>NextPDF renders <strong>HTML and CSS</strong> directly into PDF pages,<em>in-process</em>.</p><ul> <li>Headings, paragraphs, bold and italic</li> <li>Lists, tables, inline styles</li></ul>HTML;
$doc->writeHtml($html);$doc->save(__DIR__ . '/html-basic.pdf');Se o mesmo documento exigisse CSS moderno arbitrário com fidelidade exata de navegador, a chamada seria writeHtmlChrome($html) — mesmo documento, caminho de renderização diferente e uma dependência deliberada do renderizador de navegador opcional.
Equívoco comum
Seção intitulada “Equívoco comum”O equívoco recorrente é tratar um motor de HTML para PDF como “basicamente um navegador.” Ele não é, e não afirma ser. Um navegador é uma implementação vasta e continuamente atualizada de toda a plataforma web. O motor in-process do NextPDF é um subconjunto alinhado às especificações e focado em layout de documentos. O modelo mental honesto é “um motor de CSS competente para documentos de impressão”, não “Chrome em PHP.” Quando você realmente precisa da plataforma completa, é para isso que serve writeHtmlChrome(). É um caminho separado, de adesão explícita, com sua própria pegada operacional, não um fallback silencioso.
Um segundo equívoco é presumir que o caminho do navegador apenas “renderiza a página pela rede.” É o oposto, por construção. O ponto de junção de delegação sempre renderiza com o acesso de rede a sub-recursos bloqueado — sem imagens, fontes, folhas de estilo ou frames remotos — de modo que não pode se tornar um vetor de requisições de saída. Fidelidade de pixels, sim; saída de rede aberta, não.
Limites e fronteiras
Seção intitulada “Limites e fronteiras”Esta página explica o formato do pipeline e a escolha entre in-process e navegador. Ela não é uma matriz de suporte a CSS. As propriedades, módulos e seletores exatos que o motor in-process cobre são definidos pelo código e por seus testes de conformidade, não por esta visão geral. Essa cobertura evolui. O caminho de delegação ao navegador exige uma extensão opcional e um binário Chrome/Chromium. A configuração, as características operacionais e a estrutura interna dessa extensão estão fora do escopo aqui e são documentadas junto com aquele pacote. “In-process” descreve o caminho padrão writeHtml(). Não é uma afirmação de que todo caminho de renderização evita um subprocesso. As afirmações arquiteturais estão corretas na data de revisão desta página. As fontes autoritativas são src/Html/, o ADR-001 e o ADR-010 no repositório core.
O motor de CSS in-process é uma capacidade do Core. O ponto de junção de delegação ao navegador é uma extensão opcional, apresentada aqui apenas no nível de capacidade:
| Edition | Availability |
|---|---|
| Core | O Core fornece o motor de HTML/CSS in-process (writeHtml). |
| Pro | O caminho de delegação ao navegador é uma extensão complementar opcional, independente do nível de edição. |
| Enterprise | O caminho de delegação ao navegador é uma extensão complementar opcional, independente do nível de edição. |
Documentos relacionados
Seção intitulada “Documentos relacionados”- O modelo de pipeline — onde o caminho de conteúdo HTML se encaixa no fluxo geral do documento.
- Quando não usar o NextPDF — o limite honesto, incluindo onde o caminho do navegador ou outra ferramenta faz sentido.
- O guia de decisão de integração — como escolher entre o motor in-process e um renderizador para o seu caso.
Glossário
Seção intitulada “Glossário”- Renderização in-process — converter HTML/CSS em PDF dentro do processo PHP, sem navegador ou subprocesso padrão (
writeHtml()). - Single-pass / streaming — consumir um fluxo de tokens da esquerda para a direita sem reter uma árvore DOM completa (ADR-001).
- Cascade — o processo do CSS que resolve declarações concorrentes em um valor por propriedade por origem, importância, camada, especificidade e ordem.
- Formatting context — o ambiente de layout que uma caixa estabelece e que governa como o conteúdo in-flow dela é posicionado.
- Contrato de camadas do motor — o conjunto de regras imposto (ADR-010) que define o que cada uma das camadas de parsing, estilo, layout, pintura e paged media pode fazer.
- Ponto de junção de delegação ao navegador — o caminho opcional
writeHtmlChrome()que renderiza por meio de um navegador headless com o acesso de rede a sub-recursos bloqueado.