DOMParser.stuffStyleIntoHead: when doc.body.innerHTML silently drops your CSS
TLDR: DOMParser respects the HTML spec: <style> tags belong in <head>, so that is where it puts them. If you parse a document fragment that starts with <style>...</style> and then read doc.body.innerHTML, you get the body content only. Your styles vanish silently. The fix is to query doc.head.querySelectorAll('style') and include those rules explicitly in your output wrapper.
The bug class
DOMParser does not leave HTML exactly where you put it. It parses according to the HTML spec, which means <style>, <title>, <base>, and <meta> elements go into <head> even if your input string had them before any body content.
This is a problem when you do:
const doc = new DOMParser().parseFromString(html, 'text/html');
// ... mutate the DOM (embed images, etc.) ...
html = doc.body.innerHTML; // styles are gone!
The styles were in doc.head the whole time. doc.body.innerHTML never had them.
Why the extracted font CSS was invisible
A PDF extraction pipeline generates font-specific CSS rules for every unique font in the document. These are emitted as a <style> block prepended to the page HTML:
<style>
.pdf-doc .f0 { font-size: 12pt; font-family: "Times New Roman", serif; }
.pdf-doc .f1 { font-size: 10pt; font-family: "Arial", sans-serif; }
/ ... potentially 20-50 rules ... /
</style>
<article class="pdf-doc">
<!-- pages of content with class="f0", "f1", etc. -->
</article>
The standalone export function parsed this string, embedded images, then output doc.body.innerHTML wrapped in a minimal HTML template. The <article> was preserved. The <style> block was not. Every font class became inert. The exported file rendered in the browser's default font at the default size.
The fix
Extract the <style> elements from the document head before reading the body:
const styleTags = doc.head?.querySelectorAll('style') || [];
const fontCss = Array.from(styleTags)
.map(s => s.outerHTML)
.join('\n');
html = doc.body.innerHTML;
const exportedHead = [ '<meta charset="utf-8"/>', <title>${title}</title>, fontCss, '<style>body{font-family:sans-serif;max-width:1000px;margin:0 auto;}</style>', ].join('\n');
Now the exported HTML has both the body content and the font styles that give it the correct appearance.
How to prevent this class
Any time you use DOMParser to process HTML that contains <style> blocks and then read doc.body.innerHTML, verify that the styles are still there. The rule is: DOMParser puts metadata elements in <head>. If you discard the document object without extracting from head, you lose them.
For a quick test: log doc.head.innerHTML and doc.body.innerHTML separately before using either. If your input had a <style> tag and doc.body.innerHTML does not contain it, your styles went to <head>.
One generalizable lesson
DOMParser is not a string-to-string transformation. It is a spec-compliant parser that restructures your input to match the HTML document model. Always check where the parser placed your elements before reading the output. The spec is the spec, even when it is inconvenient.