mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 06:06:37 +03:00
Each problem-space fixture is now a single file with two columns: left
for cases that should flag, right for cases that should not. Matches the
icon-tile-stack convention and makes browser-based visual review easier.
The pass column proves that no false positives leak from look-alike
patterns next to the real anti-patterns.
Merged (4 pairs → 4 files)
- color-should-{flag,pass}.html → color.html
- motion-should-{flag,pass}.html → motion.html
- glow-should-{flag,pass}.html → glow.html
- layout-should-{flag,pass}.html → layout.html
Left untouched
- should-{flag,pass}.html — used by the CLI smoke tests in
detect-antipatterns.test.js, which need a known-clean fixture for the
exit-code-0 path.
- typography-should-{flag,pass}.html — all three typography rules
(overused-font, single-font, flat-type-hierarchy) are page-level and
fundamentally can't share a page with their pass cases. Loading two
font stacks suppresses single-font; varied sizes suppress flat-type-
hierarchy. Documented in the test file.
Test calibration
- Hardcoded the jsdom finding counts (motion: 2 bounce + 2 layout-
transition; glow: 1 dark-glow). Real browser sees more because
jsdom doesn't fully apply class-based styles, but the pass-column
count is reliably 0. Browser-verified all 4 fixtures show expected
flag counts and zero pass-column false positives.
Fixture chrome fixes
- Sub-section labels (.col h3) now use #64748b instead of #94a3b8 so
the fixture's own UI doesn't trigger low-contrast. glow.html got a
CSS restructure into card-dark/card-light/card-medium variants so
every text/background pairing meets WCAG AA. layout.html's "card
with image" gradient changed from blue→purple to amber→rose so it
doesn't trip ai-color-palette.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
161 lines
7.3 KiB
HTML
161 lines
7.3 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Motion Anti-Patterns — Should Flag vs Should Pass</title>
|
|
<style>
|
|
/* ─── Two-column fixture convention ─────────────────────────────
|
|
Left column = should flag. Right column = should pass.
|
|
Tests assert (a) every flag-column rule fires and (b) the total
|
|
finding count matches the number of flag cases (no false
|
|
positives leaking from the pass column).
|
|
──────────────────────────────────────────────────────────── */
|
|
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; }
|
|
.demo { padding: 14px 16px; background: white; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.08); margin-bottom: 10px; }
|
|
.demo h4 { font-weight: 600; font-size: 13px; margin: 0; }
|
|
.demo p { font-size: 12px; color: #6b7280; margin: 4px 0 0; }
|
|
|
|
/* ── FLAG: bounce / elastic easing ── */
|
|
@keyframes bounce-keyframe {
|
|
0%, 100% { transform: translateY(0); }
|
|
50% { transform: translateY(-10px); }
|
|
}
|
|
.bounce-animation { animation: bounce-keyframe 1s infinite; }
|
|
.elastic-transition { transition: transform 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55); }
|
|
|
|
/* ── FLAG: layout property transitions ── */
|
|
.width-transition { transition: width 0.3s ease; }
|
|
.height-transition { transition: height 0.4s ease-out; }
|
|
.padding-transition { transition: padding 0.2s linear; }
|
|
.margin-transition { transition: margin 0.3s ease-in; }
|
|
.max-height-transition { transition: max-height 0.5s ease; }
|
|
.multi-layout-transition { transition: width 0.3s ease, height 0.3s ease; }
|
|
.mixed-transition { transition: width 0.3s ease, opacity 0.3s ease; }
|
|
.transition-property-width { transition-property: width; transition-duration: 0.3s; }
|
|
|
|
/* ── PASS: good easing ── */
|
|
@keyframes fade-in-keyframe {
|
|
from { opacity: 0; transform: translateY(8px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
.fade-in-good { animation: fade-in-keyframe 0.4s cubic-bezier(0.16, 1, 0.3, 1); }
|
|
.ease-out-quart { transition: transform 0.4s cubic-bezier(0.25, 1, 0.5, 1); }
|
|
.ease-out-expo { transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1); }
|
|
|
|
/* ── PASS: safe transitions ── */
|
|
.transform-transition { transition: transform 0.3s ease-out; }
|
|
.opacity-transition { transition: opacity 0.2s ease; }
|
|
.color-transition { transition: color 0.15s ease, background-color 0.15s ease; }
|
|
.shadow-transition { transition: box-shadow 0.2s ease; }
|
|
.all-transition { transition: all 0.3s ease; }
|
|
.multi-safe-transition { transition: transform 0.3s ease, opacity 0.3s ease, box-shadow 0.2s ease; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="grid">
|
|
<!-- ════════════════════════════════════════════════════════════
|
|
LEFT COLUMN: should flag
|
|
═══════════════════════════════════════════════════════════ -->
|
|
<div class="col" data-col="flag">
|
|
<h2>Should flag</h2>
|
|
|
|
<h3>Bounce / elastic easing</h3>
|
|
<div class="demo bounce-animation">
|
|
<h4>CSS bounce animation</h4>
|
|
<p>animation: bounce 1s infinite</p>
|
|
</div>
|
|
<div class="demo elastic-transition">
|
|
<h4>Elastic cubic-bezier</h4>
|
|
<p>cubic-bezier(0.68, -0.55, 0.265, 1.55)</p>
|
|
</div>
|
|
|
|
<h3>Layout property transitions</h3>
|
|
<div class="demo width-transition">
|
|
<h4>transition: width</h4>
|
|
<p>Animating width causes layout thrash.</p>
|
|
</div>
|
|
<div class="demo height-transition">
|
|
<h4>transition: height</h4>
|
|
<p>Animating height causes layout thrash.</p>
|
|
</div>
|
|
<div class="demo padding-transition">
|
|
<h4>transition: padding</h4>
|
|
<p>Animating padding causes layout thrash.</p>
|
|
</div>
|
|
<div class="demo margin-transition">
|
|
<h4>transition: margin</h4>
|
|
<p>Animating margin causes layout thrash.</p>
|
|
</div>
|
|
<div class="demo max-height-transition">
|
|
<h4>transition: max-height</h4>
|
|
<p>Use grid-template-rows instead.</p>
|
|
</div>
|
|
<div class="demo multi-layout-transition">
|
|
<h4>transition: width, height</h4>
|
|
<p>Multiple layout properties.</p>
|
|
</div>
|
|
<div class="demo mixed-transition">
|
|
<h4>transition: width, opacity</h4>
|
|
<p>Layout property mixed with OK property.</p>
|
|
</div>
|
|
<div class="demo transition-property-width">
|
|
<h4>transition-property: width</h4>
|
|
<p>Longhand form.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ════════════════════════════════════════════════════════════
|
|
RIGHT COLUMN: should pass
|
|
═══════════════════════════════════════════════════════════ -->
|
|
<div class="col" data-col="pass">
|
|
<h2>Should pass</h2>
|
|
|
|
<h3>Good easing</h3>
|
|
<div class="demo fade-in-good">
|
|
<h4>Smooth fade in</h4>
|
|
<p>animation: fadeIn with exponential ease-out</p>
|
|
</div>
|
|
<div class="demo ease-out-quart">
|
|
<h4>Ease-out quart</h4>
|
|
<p>cubic-bezier(0.25, 1, 0.5, 1) — smooth deceleration</p>
|
|
</div>
|
|
<div class="demo ease-out-expo">
|
|
<h4>Ease-out expo</h4>
|
|
<p>cubic-bezier(0.16, 1, 0.3, 1) — natural feel</p>
|
|
</div>
|
|
|
|
<h3>Safe transitions (transform / opacity / color only)</h3>
|
|
<div class="demo transform-transition">
|
|
<h4>transition: transform</h4>
|
|
<p>Transform is GPU-accelerated and safe.</p>
|
|
</div>
|
|
<div class="demo opacity-transition">
|
|
<h4>transition: opacity</h4>
|
|
<p>Opacity is GPU-accelerated and safe.</p>
|
|
</div>
|
|
<div class="demo color-transition">
|
|
<h4>transition: color, background-color</h4>
|
|
<p>Color transitions are paint-only, no layout.</p>
|
|
</div>
|
|
<div class="demo shadow-transition">
|
|
<h4>transition: box-shadow</h4>
|
|
<p>Shadow transitions are paint-only.</p>
|
|
</div>
|
|
<div class="demo all-transition">
|
|
<h4>transition: all</h4>
|
|
<p>Too common to flag — usually paired with transform/opacity.</p>
|
|
</div>
|
|
<div class="demo multi-safe-transition">
|
|
<h4>transition: transform, opacity, box-shadow</h4>
|
|
<p>Multiple safe properties combined.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script src="/js/detect-antipatterns-browser.js"></script>
|
|
</body>
|
|
</html>
|