This commit is contained in:
Josh at WLTechBlog
2025-12-09 13:48:27 -07:00
parent 6ad3d6e40e
commit 6b26c13add
2 changed files with 137 additions and 47 deletions

View File

@@ -0,0 +1,83 @@
# 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