Engineering Journal
Pdf Processor
Pdf Processor

DOMParser.stuffStyleIntoHead: when doc.body.innerHTML silently drops your CSS

2026-07-17

TLDR

Parsing HTML strings using DOMParser.parseFromString() automatically relocates <style> tags into the generated document's <head> element per the HTML parsing specification. Serializing output by reading doc.body.innerHTML silently discards all prepended <style> blocks, stripping extracted font rules. To preserve styles, query doc.head.querySelectorAll('style') and concatenate the outer HTML of all style tags into your final document wrapper.
Serialization TargetContains Body ContentContains <style> BlocksExtracted Font Fidelity
doc.body.innerHTML OnlyYesNo (Relocated to <head>)Fails (Styles stripped completely)
doc.head Styles + doc.bodyYesYes (Re-assembled explicitly)100% (Full font styling preserved)

Technical defect analysis

Our PDF export pipeline generates dynamic CSS classes (.f0, .f1) and prepends a <style> block to extracted HTML fragments:

<!-- INPUT HTML STRING -->
<style>
  .pdf-doc .f0 { font-size: 12pt; font-family: "Times New Roman", serif; }
  .pdf-doc .f1 { font-size: 10pt; font-family: "Arial", sans-serif; }
</style>
<article class="pdf-doc">
  <p class="f0">Extracted PDF Text Content</p>
</article>

When processing images or DOM mutations using DOMParser:

// DEFECTIVE IMPLEMENTATION: Reading body.innerHTML drops head styles!
const parser = new DOMParser();
const doc = parser.parseFromString(rawHtmlString, 'text/html');

// ... perform DOM mutations on doc ...

const exportedHtml = doc.body.innerHTML; // SILENT LOSS: <style> tags were moved to doc.head!

Because DOMParser moves <style> tags into doc.head, doc.body.innerHTML returns only the <article> element, stripping all CSS font declarations from exported documents.


Remediation: head style extraction & re-assembly

Extract all <style> elements from doc.head before serializing doc.body.innerHTML:

export function serializeParsedDocument(doc, documentTitle = 'Extracted Document') {
  // 1. Extract all style tags relocated to <head> by DOMParser
  const styleElements = doc.head ? Array.from(doc.head.querySelectorAll('style')) : [];
  const extractedCss = styleElements.map(style => style.outerHTML).join('\n');

// 2. Extract body HTML const bodyHtml = doc.body ? doc.body.innerHTML : '';

// 3. Assemble complete HTML5 document structure return &lt;!DOCTYPE html&gt; &lt;html lang="en"&gt; &lt;head&gt; &lt;meta charset="utf-8"/&gt; &lt;title&gt;${escapeHtml(documentTitle)}&lt;/title&gt; ${extractedCss} &lt;/head&gt; &lt;body&gt; ${bodyHtml} &lt;/body&gt; &lt;/html&gt;; }

Rule of thumb: Extract <style> tags from doc.head whenever serializing HTML strings parsed by DOMParser.
Read this post in the full Engineering Journal →