# Contrast Check Fix: Container Element False Positives ## Issue Description The automated contrast checker was incorrectly flagging parent container elements (DIVs) instead of the actual text elements (H2, P, etc.) when checking color contrast. ### Example from the Field On https://visionleadership.org/gala-sponsorship/: **Element 18 (H2 heading):** - Tag: `H2` - Text: "Gala Presenting Sponsor" - Color: `rgb(255, 255, 255)` ✅ WHITE - Background: `rgba(0, 0, 0, 0)` - transparent - Parent background: `rgb(12, 113, 195)` - BLUE - **Actual contrast ratio: 5.04:1 ✅ PASSES AA** **Element 17 (parent DIV):** - Tag: `DIV` - Color: `rgb(61, 61, 61)` - DARK GRAY - Background: `rgb(12, 113, 195)` - BLUE - **Computed contrast ratio: 2.15:1 ❌ FALSE POSITIVE** ### Root Cause The contrast checker was using the selector: ```javascript "p, h1, h2, h3, h4, h5, h6, a, button, span, div, li, td, th, label, input, textarea" ``` When a DIV container had text content (from child elements like H2), it was being checked using the DIV's computed text color (dark gray) instead of the actual H2's color (white). ## Solution Added logic to skip container elements (DIV, SPAN) that don't have **direct text nodes** (text that is a direct child, not in descendant elements). ### Implementation ```javascript // Skip container elements that don't have direct text nodes const hasDirectTextContent = Array.from(element.childNodes).some(node => node.nodeType === Node.TEXT_NODE && node.textContent.trim().length > 0 ); // For container elements (div, span), only check if they have direct text // For semantic text elements (h1-h6, p, a, button, etc.), always check const isSemanticTextElement = ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'P', 'A', 'BUTTON', 'LABEL', 'LI', 'TD', 'TH'].includes(element.tagName); const isContainerElement = ['DIV', 'SPAN'].includes(element.tagName); if (isContainerElement && !hasDirectTextContent) { // Skip this container - its children will be checked separately return; } ``` ### Behavior After Fix 1. **Semantic text elements** (H1-H6, P, A, BUTTON, LABEL, LI, TD, TH) are **always checked**, regardless of whether they have direct text content 2. **Container elements** (DIV, SPAN) are **only checked if they have direct text nodes** 3. **Container elements without direct text** are **skipped** - their child elements will be checked separately ## Test Results After the fix, the contrast check correctly identifies: - ✅ H2 "Gala Presenting Sponsor": White text on blue background = **5.04:1 PASSES AA** - ✅ H2 "Gala Bar Sponsor": White text on blue background = **5.04:1 PASSES AA** - ✅ H2 "Table Sponsor": White text on blue background = **5.04:1 PASSES AA** - ✅ H2 "RSVP Gala Ticket": White text on blue background = **5.04:1 PASSES AA** - ✅ Parent DIVs are **not checked** (correctly skipped) ## Files Modified - `daemon/daemon.go` - Lines 9221-9241: Added logic to skip container elements without direct text content ## Impact - **Eliminates false positives** from parent containers - **Improves accuracy** of contrast checking - **Reduces noise** in accessibility reports - **No impact** on legitimate contrast violations