style(preview): cross-browser immersive scrollbar support

Page-level scrollbar:
- WebKit: ::-webkit-scrollbar with 3px width, transparent track,
  6% white thumb → 18% on hover
- Firefox: scrollbar-width:thin + scrollbar-color on #preview-area, #panel
- Legacy Edge/IE: -ms-overflow-style: -ms-autohiding-scrollbar
- Chrome 108+: overflow:overlay via @supports (scrollbar floats,
  no layout shift)

Iframe content (email preview):
- Same cross-browser treatment injected into every rendered template
- Dark email themes get dark scrollbar (rgba(0,0,0,.08))
- Light email themes also covered (6% black is subtle on any bg)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
KenanZhuandClaude Opus 4.8 committed 2026-06-04 14:38:55 +08:00
1 parent dc602a7dde
commit 87d1603187
1 file changed
+10 -5
+10 -5
View File
@@ -74,14 +74,19 @@ body{font-family:system-ui,-apple-system,sans-serif;background:var(--bg);color:v
.message-error{background:rgba(248,113,113,0.08);color:rgba(248,113,113,0.75);border-color:rgba(248,113,113,0.15)} .message-error{background:rgba(248,113,113,0.08);color:rgba(248,113,113,0.75);border-color:rgba(248,113,113,0.15)}
.message code{background:rgba(0,0,0,0.12);padding:1px 6px;border-radius:3px} .message code{background:rgba(0,0,0,0.12);padding:1px 6px;border-radius:3px}
/* Scrollbar — ultra-thin, barely visible, immersive */ /* ── Immersive scrollbar — cross-browser ── */
/* WebKit (Chrome, Safari, Edge 79+) */
::-webkit-scrollbar{width:3px;height:3px} ::-webkit-scrollbar{width:3px;height:3px}
::-webkit-scrollbar-track{background:transparent} ::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:rgba(255,255,255,.06);border-radius:3px} ::-webkit-scrollbar-thumb{background:rgba(255,255,255,.06);border-radius:3px}
::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.15)} ::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.18)}
::-webkit-scrollbar-corner{background:transparent} ::-webkit-scrollbar-corner{background:transparent}
/* Firefox */ /* Firefox 64+ */
*{scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.06) transparent} #preview-area,#panel{scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.06) transparent}
/* Legacy Edge / IE: auto-hide */
#preview-area,#panel{-ms-overflow-style:-ms-autohiding-scrollbar}
/* Chrome 108+: overlay (no layout shift) */
@supports(overflow:overlay){#preview-area,#panel{overflow:overlay}}
@media(max-width:850px){#panel{display:none}#topbar .hint{display:none}} @media(max-width:850px){#panel{display:none}#topbar .hint{display:none}}
</style> </style>
@@ -191,7 +196,7 @@ function render() {
const raw = rendered[state.theme]?.[state.template]; const raw = rendered[state.theme]?.[state.template];
let content = raw ? transform(raw, state.client) : '<p style=\"color:red;padding:20px\">Not found: '+state.theme+'/'+state.template+'</p>'; let content = raw ? transform(raw, state.client) : '<p style=\"color:red;padding:20px\">Not found: '+state.theme+'/'+state.template+'</p>';
// Inject invisible scrollbar into iframe content for immersive preview // Inject invisible scrollbar into iframe content for immersive preview
content = content.replace('</head>', '<style>html{scrollbar-width:thin;scrollbar-color:#fff1 transparent}html::-webkit-scrollbar{width:3px;height:3px}html::-webkit-scrollbar-track{background:transparent}html::-webkit-scrollbar-thumb{background:rgba(0,0,0,.08);border-radius:3px}html::-webkit-scrollbar-thumb:hover{background:rgba(0,0,0,.2)}</style></head>'); content = content.replace('</head>', '<style>html{scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.06) transparent;-ms-overflow-style:-ms-autohiding-scrollbar}html::-webkit-scrollbar{width:3px;height:3px}html::-webkit-scrollbar-track{background:transparent}html::-webkit-scrollbar-thumb{background:rgba(0,0,0,.08);border-radius:3px}html::-webkit-scrollbar-thumb:hover{background:rgba(0,0,0,.22)}@supports(overflow:overlay){html{overflow:overlay}}</style></head>');
frame.onload = function() { frame.onload = function() {
loading.style.display = 'none'; loading.style.display = 'none';