Badges: use position:fixed for print centering — bypasses all ancestor layout issues

This commit is contained in:
Scott Idem
2026-03-12 18:25:31 -04:00
parent 5410bb4a8c
commit c867795f4d

View File

@@ -162,41 +162,29 @@
<style>
@media print {
/* Full-page reset.
app.css sets `overflow: hidden` on html + body globally — override it
so body/html fill the full page (not just the badge width). */
app.css sets overflow:hidden on html + body — override so they don't
create BFCs that shrink to content. */
html, body {
display: block !important;
width: 100% !important;
height: 100% !important;
overflow: visible !important;
margin: 0 !important;
padding: 0 !important;
overflow: visible !important;
}
/* Hide app chrome */
/* Hide all app chrome */
.submenu { display: none !important; }
/* #ae_main_content becomes the positioning context for the badge.
It fills the full page (100%×100%), and the badge is absolutely
centered within it.
Why not flex: Firefox respects the printer driver's minimum hardware
margins even with @page { margin: 0 }. This makes the available
content area slightly smaller than 100%, throwing off flex centering.
CSS transform-based centering (translate -50%,-50%) is immune to
this: it centers relative to the containing block dimension, which
Firefox computes correctly even when printer margins are applied.
Why not display:contents on this element: #ae_main_content has
overflow:auto. Per spec, display:contents cannot override an element
with overflow clipping; Firefox keeps it as a block box. We reset it
to a positioned block instead. */
/* #ae_main_content: make it a transparent, non-interfering passthrough block.
We cannot use display:contents here — it has overflow:auto, and per spec
display:contents cannot override overflow-clipping elements (Firefox
enforces this strictly). We just strip its visual/layout effects instead. */
#ae_main_content {
position: relative !important;
display: block !important;
position: static !important;
width: 100% !important;
max-width: none !important;
height: 100% !important;
height: auto !important;
min-height: 0 !important;
overflow: visible !important;
background: transparent !important;
@@ -205,26 +193,37 @@
}
/* .main_content and #badge_render_area have no overflow constraints,
so display:contents dissolves their boxes in all browsers.
.event_badge_wrapper emerges as a direct child of #ae_main_content. */
so display:contents safely dissolves their boxes in all browsers. */
.main_content,
#badge_render_area {
display: contents !important;
}
/* Center the badge using CSS transforms — the most reliable cross-browser
print centering method; unaffected by printer margin variations. */
/* Center badge using position:fixed.
Why fixed instead of absolute/flex:
- position:fixed in print positions relative to the @page content area,
completely bypassing the ancestor hierarchy (no containing-block height
dependency, no overflow-clip interference, no flex-parent issues).
- top/left:50% + translate(-50%,-50%) centers within the page content area.
- Firefox applies physical printer hardware margins even with @page{margin:0};
this shrinks the content area slightly but top:50%/left:50% still centers
within whatever area the browser gives us it's immune to asymmetric margins.
- Chrome: identical behavior to absolute+flex centering but more robust.
- min-height:0 overrides the Tailwind min-h-[6.0in] class on this wrapper;
badge_front/back provide their own dimensions. */
.event_badge_wrapper {
position: absolute !important;
position: fixed !important;
top: 50% !important;
left: 50% !important;
transform: translate(-50%, -50%) !important;
min-height: 0 !important;
max-width: none !important;
margin: 0 !important;
padding: 0 !important;
gap: 0 !important;
}
/* Never split the front or back across pages */
/* Never split front/back across pages */
.badge_front,
.badge_back {
break-inside: avoid;
@@ -242,7 +241,7 @@
outline: 4px solid blue !important;
outline-offset: -4px !important;
}
/* Red = #ae_main_content — should be VISIBLE and fill the page (same as blue). */
/* Red = #ae_main_content — block passthrough, should fill page width/height. */
#ae_main_content {
outline: 3px dashed red !important;
outline-offset: -6px !important;
@@ -256,7 +255,7 @@
outline: 3px dashed purple !important;
outline-offset: -12px !important;
}
/* Cyan = the actual badge — should be dead-center */
/* Cyan = the actual badge — should be dead-center on page */
.event_badge_wrapper {
outline: 3px solid cyan !important;
outline-offset: 2px !important;