mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 22:26:38 +03:00
- parseAnyColor now covers oklab(), hsl()/hsla(), hwb(), and ~35 common named colors on top of rgb/rgba/hex/oklch, so checkGlow sees the color regardless of authoring format (Chrome preserves oklch() in computed styles, which the old rgba-only match silently passed). - checkGlow gains a second tell: a zero-offset chromatic box/text-shadow with blur > 4px is flagged on ANY background (the halo pattern); achromatic zero-offset shadows and focus rings stay legal. The existing chromatic-blur-on-dark-background rule is unchanged in semantics but now parses every color format. - text-shadow is checked wherever box-shadow was (browser DOM path with inherited-value dedupe, static engine via new textShadow cascade support, text engines). - The page-level text scan (regex engine + checkHtmlPatterns) is now a shared scanCssTextForGlow that resolves single-level var() refs against custom properties collected from the same text; unresolvable var() in a shadow color position is skipped, never guessed. Its dark-page heuristic accepts var()/oklch backgrounds but only when declared at root scope (body/html/:root or body inline style). - dark-glow keeps its id; registry name/description updated to cover both cases. Validated: three eval repro samples with oklch / var(--x) glows that previously produced zero findings now flag on the static CLI path; ten known-good largerun samples stay clean except one with genuine amber status-dot halos (0 0 12px oklch(.73 .17 65/.4)). Note: cli/engine/detect-antipatterns-browser.js and the extension detector are generated and still need 'node scripts/build-browser-detector.js' + 'node scripts/build-extension.js' once builds are unblocked. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
231 lines
10 KiB
HTML
231 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Dark Glow Anti-Patterns — Should Flag vs Should Pass</title>
|
|
<style>
|
|
/* Two-column fixture: left = should flag, right = should pass.
|
|
The dark-glow rule fires when a colored box-shadow appears on a
|
|
child whose ancestor has a dark background. Each column wraps
|
|
its dark-context cases in its own .dark-context section so the
|
|
parent-bg lookup behaves predictably regardless of layout. */
|
|
body { font-family: system-ui, sans-serif; background: #f9fafb; padding: 24px; margin: 0; }
|
|
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 1200px; margin: 0 auto; }
|
|
.col h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }
|
|
.col h3 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; margin: 24px 0 8px; color: #64748b; }
|
|
.dark-context { background: #111827; padding: 16px; border-radius: 12px; }
|
|
.dark-context + .dark-context { margin-top: 12px; }
|
|
/* Card variants: explicit dark vs light pairings, both WCAG AA compliant */
|
|
.card { padding: 14px 16px; border-radius: 10px; margin-bottom: 10px; }
|
|
.card h4 { font-weight: 600; font-size: 13px; margin: 0; }
|
|
.card p { font-size: 12px; margin: 4px 0 0; }
|
|
.card-dark { background: #1f2937; }
|
|
.card-dark h4 { color: #f9fafb; }
|
|
.card-dark p { color: #cbd5e1; }
|
|
.card-light { background: white; }
|
|
.card-light h4 { color: #0f172a; }
|
|
.card-light p { color: #475569; }
|
|
|
|
/* ── FLAG: dark background + colored glow ── */
|
|
.glow-blue { box-shadow: 0 0 20px rgba(59, 130, 246, 0.4); }
|
|
.glow-purple { box-shadow: 0 0 25px rgba(139, 92, 246, 0.35); }
|
|
.glow-cyan { box-shadow: 0 0 15px rgba(6, 182, 212, 0.5); }
|
|
.glow-multi { box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3), 0 0 30px rgba(168, 85, 247, 0.3); }
|
|
|
|
/* ── FLAG: modern color formats, var() refs, text-shadow ── */
|
|
:root { --fixture-glow: oklch(0.78 0.14 155); }
|
|
.glow-oklch { box-shadow: 0 0 18px oklch(0.72 0.15 195 / 0.5); }
|
|
.glow-hex { box-shadow: 0 0 16px #3b82f6; }
|
|
.glow-hsl { box-shadow: 0 0 22px hsl(280, 80%, 60%); }
|
|
.glow-var { box-shadow: 0 0 10px var(--fixture-glow); }
|
|
.glow-text h4 { text-shadow: 0 0 12px #22d3ee; }
|
|
/* Zero-offset chromatic halo is slop on light backgrounds too */
|
|
.glow-light-oklch { box-shadow: 0 0 20px oklch(0.65 0.2 300 / 0.45); }
|
|
|
|
/* ── PASS: same dark/light backgrounds, but neutral or no glow ── */
|
|
.light-colored-shadow { box-shadow: 0 2px 4px rgba(59, 130, 246, 0.15); }
|
|
.dark-normal-shadow { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); }
|
|
.dark-focus-ring { box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.5); }
|
|
.dark-subtle-shadow { box-shadow: 0 1px 3px rgba(59, 130, 246, 0.2); }
|
|
.dark-elevated-sm { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); }
|
|
.dark-elevated-md { box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.4); }
|
|
.dark-elevated-lg { box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5); }
|
|
.dark-elevated-inset { box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3); }
|
|
.dark-elevated-multi { box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3), 0 1px 3px rgba(0, 0, 0, 0.2); }
|
|
.elevated-sm-light { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); }
|
|
.elevated-md-light { box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); }
|
|
.elevated-warm-light { box-shadow: 0 10px 30px -5px rgba(0, 0, 0, 0.15); }
|
|
/* Medium-gray card: lighter than dark mode, used to demonstrate "not dark enough" for glow detection. White text for AA contrast. */
|
|
.card-medium { background: #6b7280; }
|
|
.card-medium h4 { color: #ffffff; }
|
|
.card-medium p { color: #ffffff; }
|
|
.medium-gray-shadow { box-shadow: 0 2px 4px rgba(59, 130, 246, 0.3); }
|
|
/* Offset chromatic drop shadow on a light background: a real drop
|
|
shadow, not a halo — must NOT flag under the zero-offset rule.
|
|
(Element path; the page-level text scan caps at one finding.) */
|
|
.light-offset-colored { box-shadow: 0 8px 20px rgba(59, 130, 246, 0.25); }
|
|
/* Achromatic zero-offset shadow: soft ambient elevation, stays legal */
|
|
.light-soft-neutral { box-shadow: 0 0 24px rgba(0, 0, 0, 0.15); }
|
|
/* Offset neutral text-shadow on dark card: legibility aid, not a glow */
|
|
.dark-text-offset h4 { text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="grid">
|
|
<!-- ════════════════════════════════════════════════════════════
|
|
LEFT COLUMN: should flag (dark page + colored glows)
|
|
═══════════════════════════════════════════════════════════ -->
|
|
<div class="col" data-col="flag">
|
|
<h2>Should flag</h2>
|
|
|
|
<h3>CSS colored glows on dark background</h3>
|
|
<div class="dark-context">
|
|
<div class="card card-dark glow-blue">
|
|
<h4>Blue glow</h4>
|
|
<p>box-shadow: 0 0 20px rgba(59, 130, 246, 0.4)</p>
|
|
</div>
|
|
<div class="card card-dark glow-purple">
|
|
<h4>Purple glow</h4>
|
|
<p>box-shadow: 0 0 25px rgba(139, 92, 246, 0.35)</p>
|
|
</div>
|
|
<div class="card card-dark glow-cyan">
|
|
<h4>Cyan glow</h4>
|
|
<p>box-shadow: 0 0 15px rgba(6, 182, 212, 0.5)</p>
|
|
</div>
|
|
<div class="card card-dark glow-multi">
|
|
<h4>Multi-shadow with colored glow</h4>
|
|
<p>Normal shadow + purple glow combined.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<h3>Inline-style glow (regex path)</h3>
|
|
<div class="dark-context">
|
|
<div class="card card-dark" style="box-shadow: 0 0 20px rgba(236, 72, 153, 0.5);">
|
|
<h4>Inline pink glow</h4>
|
|
<p>Inline style for regex detection path.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<h3>Modern color formats, var() refs, text-shadow</h3>
|
|
<div class="dark-context">
|
|
<div class="card card-dark glow-oklch">
|
|
<h4>OKLCH glow</h4>
|
|
<p>box-shadow: 0 0 18px oklch(0.72 0.15 195 / 0.5)</p>
|
|
</div>
|
|
<div class="card card-dark glow-hex">
|
|
<h4>Hex glow</h4>
|
|
<p>box-shadow: 0 0 16px #3b82f6</p>
|
|
</div>
|
|
<div class="card card-dark glow-hsl">
|
|
<h4>HSL glow</h4>
|
|
<p>box-shadow: 0 0 22px hsl(280, 80%, 60%)</p>
|
|
</div>
|
|
<div class="card card-dark glow-var">
|
|
<h4>Glow via var()</h4>
|
|
<p>box-shadow: 0 0 10px var(--fixture-glow)</p>
|
|
</div>
|
|
<div class="card card-dark glow-text">
|
|
<h4>Glowing text</h4>
|
|
<p>text-shadow: 0 0 12px #22d3ee on the heading.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<h3>Zero-offset halo on LIGHT background</h3>
|
|
<div class="card card-light glow-light-oklch">
|
|
<h4>Chromatic halo on light page</h4>
|
|
<p>box-shadow: 0 0 20px oklch(0.65 0.2 300 / 0.45)</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ════════════════════════════════════════════════════════════
|
|
RIGHT COLUMN: should pass
|
|
═══════════════════════════════════════════════════════════ -->
|
|
<div class="col" data-col="pass">
|
|
<h2>Should pass</h2>
|
|
|
|
<h3>Light page + colored shadow</h3>
|
|
<div class="card card-light light-colored-shadow">
|
|
<h4>Colored shadow on light background</h4>
|
|
<p>Not dark mode, colored shadow is fine.</p>
|
|
</div>
|
|
|
|
<h3>Dark cards with neutral shadows</h3>
|
|
<div class="dark-context">
|
|
<div class="card card-dark dark-normal-shadow">
|
|
<h4>Normal gray shadow on dark card</h4>
|
|
<p>Gray/black shadow is not a glow.</p>
|
|
</div>
|
|
<div class="card card-dark dark-focus-ring">
|
|
<h4>Focus ring (spread, no blur)</h4>
|
|
<p>Functional ring, not decorative glow.</p>
|
|
</div>
|
|
<div class="card card-dark dark-subtle-shadow">
|
|
<h4>Tiny blur (<5px)</h4>
|
|
<p>Too subtle to be "glowing".</p>
|
|
</div>
|
|
<div class="card card-dark dark-elevated-sm">
|
|
<h4>Small dark elevation</h4>
|
|
<p>Subtle shadow on dark card.</p>
|
|
</div>
|
|
<div class="card card-dark dark-elevated-md">
|
|
<h4>Medium dark elevation</h4>
|
|
<p>Standard dark card shadow.</p>
|
|
</div>
|
|
<div class="card card-dark dark-elevated-lg">
|
|
<h4>Large dark elevation</h4>
|
|
<p>Prominent shadow on dark card.</p>
|
|
</div>
|
|
<div class="card card-dark dark-elevated-inset">
|
|
<h4>Inset shadow</h4>
|
|
<p>Inner shadow, not a glow.</p>
|
|
</div>
|
|
<div class="card card-dark dark-elevated-multi">
|
|
<h4>Multi-shadow dark card</h4>
|
|
<p>Layered gray shadows, no color glow.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<h3>Medium-gray background (not dark enough)</h3>
|
|
<div class="card card-medium medium-gray-shadow">
|
|
<h4>Not dark enough background</h4>
|
|
<p>Medium gray doesn't qualify as "dark mode".</p>
|
|
</div>
|
|
|
|
<h3>Colored drop shadow / neutral halo on light background</h3>
|
|
<div class="card card-light light-offset-colored">
|
|
<h4>Offset colored drop shadow</h4>
|
|
<p>Real drop shadow with a color tint — not a halo.</p>
|
|
</div>
|
|
<div class="card card-light light-soft-neutral">
|
|
<h4>Soft neutral halo</h4>
|
|
<p>Achromatic zero-offset shadow is ambient elevation.</p>
|
|
</div>
|
|
|
|
<h3>Neutral text-shadow on dark card</h3>
|
|
<div class="dark-context">
|
|
<div class="card card-dark dark-text-offset">
|
|
<h4>Offset neutral text-shadow</h4>
|
|
<p>Legibility aid, not a glow.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<h3>Light elevated cards</h3>
|
|
<div class="card card-light elevated-sm-light">
|
|
<h4>Small elevation (Tailwind shadow-sm)</h4>
|
|
<p>Standard subtle card shadow.</p>
|
|
</div>
|
|
<div class="card card-light elevated-md-light">
|
|
<h4>Medium elevation (Tailwind shadow-md)</h4>
|
|
<p>Standard card shadow.</p>
|
|
</div>
|
|
<div class="card card-light elevated-warm-light">
|
|
<h4>Warm deep shadow</h4>
|
|
<p>Large spread neutral shadow.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script src="/js/detect-antipatterns-browser.js"></script>
|
|
</body>
|
|
</html>
|