body-text-viewport-edge.html

 1<!DOCTYPE html>
 2<html lang="en">
 3<head>
 4  <meta charset="UTF-8">
 5  <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6  <title>Body text viewport edge — Should Flag vs Should Pass</title>
 7  <style>
 8    /* Fixture for the body-text-viewport-edge rule. The rule fires
 9       when a <p> or <li> with substantial text content has rect.left
10       within 16px of the viewport edge (or rect.right within 16px
11       of viewport.width) AND the element has no own background-color
12       AND is not inside <nav>/<header> AND is in normal flow. */
13    body { font: 14px/1.5 system-ui, sans-serif; margin: 0; color: #111; background: #fff; }
14    .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; padding: 24px; max-width: 1400px; margin: 0 auto; }
15    .col h2 { font: 600 14px/1 system-ui; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }
16    .case-label { display: block; font-size: 12px; color: #64748b; margin: 16px 0 4px; font-style: italic; }
17    .container-good { max-width: 720px; margin: 0 auto; padding: 16px 32px; }
18    .container-tight { padding: 16px 32px; }
19    .full-bleed-section { background: #fef3c7; padding: 24px 16px; }
20    nav.site-nav { padding: 12px 24px; background: #f5f5f5; }
21    header.banner { padding: 12px 24px; background: #e5e7eb; }
22
23    /* Override the grid container's own padding so we can demonstrate
24       a paragraph that genuinely bleeds to the viewport edge inside
25       the flag column — the col itself shouldn't reset its padding. */
26    .flag-fullwidth-p { /* no container; placed directly in body via .escape */ }
27    .escape { position: relative; left: 50%; right: 50%; margin-left: -50vw; margin-right: -50vw; width: 100vw; padding: 0; }
28    .edge-list { margin: 0; padding: 0; list-style-position: inside; }
29    .edge-list li { margin: 0; }
30  </style>
31</head>
32<body>
33
34  <!-- ════════════════════════════════════════════════════════════
35       FLAG CASES — body text bleeds to viewport edge.
36       These paragraphs are placed OUTSIDE the .grid container so
37       their bounding rect actually touches the viewport edges.
38       ═══════════════════════════════════════════════════════════ -->
39  <div class="escape">
40    <p>Lucia opened this place in 1978. She cooked every night for fifty years, making the same dishes: spaghetti carbonara, eggplant parmigiana, veal saltimbocca, fresh lasagna. She did not change a single recipe in all that time. Her grandson Anthony runs the kitchen now, using the same recipes with the same care.</p>
41  </div>
42  <div class="escape">
43    <p>This second flush-to-edge paragraph confirms the rule fires on every body paragraph that touches the viewport, not just one. The rendered width should be the full viewport, with text starting essentially at x=0.</p>
44  </div>
45  <div class="escape">
46    <ul class="edge-list">
47      <li>This is a list item whose text content is substantially long enough to qualify as body content. It also runs flush against the viewport edge with no left padding.</li>
48    </ul>
49  </div>
50
51  <!-- ════════════════════════════════════════════════════════════
52       PASS CASES — body text with adequate container padding.
53       ═══════════════════════════════════════════════════════════ -->
54  <div class="grid">
55    <div class="col" data-col="pass">
56      <h2>Should pass</h2>
57
58      <span class="case-label">paragraph in centered container with 32px padding</span>
59      <div class="container-good">
60        <p>This paragraph sits inside a max-width container that's centered and has 32px horizontal padding. It does not touch the viewport edges and should not trigger the rule.</p>
61      </div>
62
63      <span class="case-label">paragraph inside &lt;nav&gt; (excluded — nav can bleed)</span>
64      <nav class="site-nav">
65        <p>This nav legitimately bleeds to the edges as a full-width header strip; the rule excludes elements inside &lt;nav&gt; or &lt;header&gt; so this does not flag.</p>
66      </nav>
67
68      <span class="case-label">paragraph inside &lt;header&gt; (excluded — header can bleed)</span>
69      <header class="banner">
70        <p>Banner headers commonly bleed to viewport edges with their own internal layout. The rule excludes &lt;header&gt; descendants.</p>
71      </header>
72
73      <span class="case-label">paragraph inside full-bleed section with own background</span>
74      <section class="full-bleed-section">
75        <p>This paragraph sits in a full-bleed section that has its own background-color set (intentional design move). The rule excludes paragraphs whose element has its own background-color.</p>
76      </section>
77
78      <span class="case-label">short label / button-ish text (excluded — &lt; 40 chars)</span>
79      <p class="container-tight">Short label.</p>
80    </div>
81
82    <div class="col" data-col="flag-notes">
83      <h2>Notes</h2>
84      <p>The flag cases above (rendered outside this grid) demonstrate the failure. The pass cases here show acceptable patterns. The rule gates aggressively to avoid false positives: it only flags &lt;p&gt; and &lt;li&gt; with &gt;40 chars whose width spans more than 50% of the viewport AND whose rect.left or rect.right is within 16px of a viewport edge AND which are not inside nav/header AND which have no own background-color AND which are in normal flow (not position:fixed/absolute).</p>
85    </div>
86  </div>
87
88  <script src="/js/detect-antipatterns-browser.js"></script>
89</body>
90</html>