fix(site-builder): editor canvas renders content with the published base reset

Published pages/Preview ship a head reset (*{margin:0;padding:0}, img block,
a inherit, body line-height 1.6 / #1f2937 / 16px); the editor canvas had none,
so h1-h6/p margins, line-height and inherited size/colour differed.

- editor.css: one commented block scoping the reset to .canvas-device-frame,
  every selector zero-specificity (:where) so inline styles / class rules win
  exactly as when published; editor chrome untouched (snapshot identical).
- tokens.ts: canvas heading/link token rules made zero-specificity too.
- utils/css-reset.ts: single source for the reset declarations (html-export
  imports it; test asserts byte-identity with the backend head and that the
  editor.css block carries the same declarations).
- scripts/e2e-canvas-parity.mjs (npm run test:browser:canvas): real editor vs
  published HTML in Firefox + Chromium, boxes within 1px + computed styles.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
shadowdaoandClaude Sonnet 5.5 committed 2026-11-01 08:23:19 -08:00
1 parent 76f0ba9ca1
commit dc415db2d3
15 files changed
+774 -6

No files matched your search

+44
View File
@@ -391,6 +391,50 @@ body {
min-height: 100%;
}
/* ==========================================================================
CANVAS = PUBLISHED BASE RESET
Published pages and Preview ship a reset in the document head
(utils/css-reset.ts CSS_RESET: `*{margin:0;padding:0}`, img{display:block},
a{color:inherit}, body line-height 1.6 / colour #1f2937 / 16px). The editor
canvas lives inside the editor document, whose own body is 13px editor
chrome with no such reset, so content looked different (default h1-h6/p/ul
margins, `normal` line-height, 13px inherited text). This block gives the
canvas FRAME -- the <body> stand-in -- and everything inside it the same
defaults.
Rules:
- Every selector is ZERO specificity (:where). The published reset is `*`
(specificity 0), so component inline styles and class rules beat it; a
plain `.canvas-device-frame *` (0,1,0) would instead beat component
<style> class rules and editor chrome rules. Do NOT remove the :where().
- Scoped to the frame, never body/:root, so panels, toolbars and Craft
overlays (all rendered outside the frame) are untouched. Editor-only
elements inside the frame style themselves with classes / inline styles,
which outrank this block.
- Declarations come from utils/css-reset.ts; css-reset.test.ts fails if
this block and that module drift apart. The font-family / colour tokens
are layered on top by CanvasTokenStyle exactly as the published head
layers them over the reset.
========================================================================== */
.canvas-device-frame {
font-size: 16px; /* UA default a published <body> gets; editor body is 13px */
font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
line-height:1.6;
color:#1f2937;
-webkit-font-smoothing:antialiased;
}
:where(.canvas-device-frame) :where(*),
:where(.canvas-device-frame) ::before,
:where(.canvas-device-frame) ::after {
box-sizing:border-box;margin:0;padding:0;
}
:where(.canvas-device-frame) :where(img) {
max-width:100%;height:auto;display:block;
}
:where(.canvas-device-frame) :where(a) {
color:inherit;
}
/* END CANVAS = PUBLISHED BASE RESET */
/* --------------------------------------------------------------------------
No Selection Message
-------------------------------------------------------------------------- */