From 8d7566cad615c9412aaa6127524e8d685adf81a7 Mon Sep 17 00:00:00 2001 From: Josh at WLTechBlog Date: Tue, 9 Dec 2025 14:06:19 -0700 Subject: [PATCH] bump --- GRADIENT_CONTRAST_FIX.md | 133 +++++++++++++++++++++++++++++++++++++++ daemon/daemon.go | 29 ++++++--- 2 files changed, 153 insertions(+), 9 deletions(-) create mode 100644 GRADIENT_CONTRAST_FIX.md diff --git a/GRADIENT_CONTRAST_FIX.md b/GRADIENT_CONTRAST_FIX.md new file mode 100644 index 0000000..90198ac --- /dev/null +++ b/GRADIENT_CONTRAST_FIX.md @@ -0,0 +1,133 @@ +# Gradient Contrast Detection Fix + +## Problem + +The contrast checking tool was reporting false positives for text on gradient backgrounds. Two specific issues were identified: + +### Issue 1: White-on-White False Positives +**Example:** Vision Leadership sponsor page (https://visionleadership.org/sponsor-opportunities/) +- **Reported:** White text `rgb(255, 255, 255)` on white background `rgb(255, 255, 255)` = 1:1 ratio (FAIL) +- **Reality:** White text on gradient background `linear-gradient(rgb(12, 90, 201) 0%, rgb(0, 0, 0) 100%)` +- **Actual Contrast:** 6.32:1 to 21:1 (PASS) + +**Root Cause:** The gradient was on a parent container (`.et_pb_section`), not directly on the text elements. The tool only checked the element itself for gradients, not parent elements. + +### Issue 2: Gradient Applied to Wrong Elements +After the initial fix, the tool became too aggressive: +- **Reported:** 54 elements with blue background `rgb(12, 90, 201)` (from gradient) +- **Reality:** Those elements were on light gray `rgb(252, 252, 252)` background +- **Root Cause:** Gradient detection walked up the tree but didn't stop when it encountered solid backgrounds + +## Solution + +Modified the gradient detection logic in `daemon/daemon.go` to: + +1. **Walk up the DOM tree** to find gradient backgrounds on parent elements +2. **Stop at solid backgrounds** - if a solid background color is found before a gradient, use the solid color +3. **Only apply gradients** when no solid background exists between the element and the gradient + +### Code Changes + +#### 1. Enhanced `analyzeGradientContrast` Function (Lines 9152-9220) + +**Before:** Only checked the element itself for gradients + +**After:** +- Walks up the DOM tree looking for gradients +- Checks for solid backgrounds at each level +- Returns `null` if a solid background is found (gradient doesn't apply) +- Only returns gradient info if no solid background blocks it + +```javascript +function analyzeGradientContrast(element, textColor) { + let current = element; + while (current && current !== document.documentElement.parentElement) { + const style = window.getComputedStyle(current); + + // Check for solid background first - if found, gradient doesn't apply + const bgColor = style.backgroundColor; + if (!isTransparent(bgColor)) { + return null; // Solid background found + } + + // Check for gradient + const bgImage = style.backgroundImage; + if (bgImage && bgImage.includes('gradient')) { + // Extract and analyze gradient colors... + return gradientInfo; + } + + current = current.parentElement; + } + return null; +} +``` + +#### 2. Updated Background Detection Logic (Lines 9305-9340) + +**Before:** Always checked for gradients, even when solid backgrounds were found + +**After:** +- Tier 1: Check for solid backgrounds via DOM tree walking +- Tier 2: Check for solid backgrounds via stacking context +- Tier 3: Only check for gradients if no solid background found +- Fallback: Use white if nothing found + +```javascript +// Tier 1: DOM tree walking for solid colors +bgColor = getEffectiveBackgroundDOMTree(element); + +// Tier 2: Stacking context analysis (if Tier 1 failed) +if (!bgColor) { + bgColor = getBackgroundFromStackingContext(element); +} + +// Tier 3: Check for gradients (only if no solid color found) +if (!bgColor) { + gradientInfo = analyzeGradientContrast(element, fgColor); + if (gradientInfo) { + bgColor = gradientInfo.colors[0]; + } +} + +// Fallback to white +if (!bgColor) { + bgColor = 'rgb(255, 255, 255)'; +} +``` + +## Testing + +After deploying the fix, test on: + +1. **Vision Leadership sponsor page** - Should correctly detect gradient and report passing contrast +2. **Elements with solid backgrounds** - Should not incorrectly apply gradients from parent containers +3. **Nested backgrounds** - Should use the closest background (solid or gradient) + +## Expected Results + +### Vision Leadership Hero Section +- **H1 "Sponsorship Opportunities That Work For You"** + - Detection method: `gradient-analysis` + - Gradient colors: `rgb(12, 90, 201)` to `rgb(0, 0, 0)` + - Worst contrast: 6.32:1 (PASS AA for large text) + - Best contrast: 21:1 (PASS AAA) + +### Elements with Solid Backgrounds +- **Text on light gray `rgb(252, 252, 252)`** + - Detection method: `dom-tree` or `stacking-context` + - Should NOT use gradient from parent + - Should calculate contrast against actual gray background + +## Deployment + +1. Build the daemon: `make daemon` +2. Build the MCP server: `make mcp` +3. Restart the cremote daemon (deployment-specific process) +4. Restart the MCP server or Augment extension to pick up changes + +## Files Modified + +- `daemon/daemon.go` - Lines 9152-9220 (gradient analysis function) +- `daemon/daemon.go` - Lines 9305-9340 (background detection logic) + diff --git a/daemon/daemon.go b/daemon/daemon.go index b39a5fc..6b5fd2e 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -9150,15 +9150,24 @@ func (d *Daemon) checkContrast(tabID string, selector string, timeout int) (*Con } // Tier 3: Gradient analysis - walks up DOM tree to find gradient backgrounds + // Only returns gradient info if no solid background color is found first function analyzeGradientContrast(element, textColor) { try { // Walk up the DOM tree to find a gradient background + // Stop if we encounter a solid background color first let current = element; while (current && current !== document.documentElement.parentElement) { const style = window.getComputedStyle(current); - const bgImage = style.backgroundImage; + + // Check for solid background color first - if found, gradient doesn't apply + const bgColor = style.backgroundColor; + if (!isTransparent(bgColor)) { + // Solid background found - gradient doesn't apply to this element + return null; + } // Check if background is a gradient + const bgImage = style.backgroundImage; if (bgImage && bgImage.includes('gradient')) { // Extract gradient colors using regex const colorRegex = /rgba?\([^)]+\)|#[0-9a-f]{3,6}/gi; @@ -9312,14 +9321,16 @@ func (d *Daemon) checkContrast(tabID string, selector string, timeout int) (*Con } } - // Tier 3: Check for gradient backgrounds (always check, even if solid color found) - // Gradients take precedence over solid colors when present - gradientInfo = analyzeGradientContrast(element, fgColor); - if (gradientInfo) { - detectionMethod = 'gradient-analysis'; - // Use a representative color from the gradient for the background_color field - // We'll use the worst-case color for reporting purposes - bgColor = gradientInfo.colors[0] || bgColor; + // Tier 3: Check for gradient backgrounds (only if no solid color found) + // Gradient analysis will return null if a solid background is found before the gradient + if (!bgColor) { + gradientInfo = analyzeGradientContrast(element, fgColor); + if (gradientInfo) { + detectionMethod = 'gradient-analysis'; + // Use a representative color from the gradient for the background_color field + // We'll use the first color for reporting purposes + bgColor = gradientInfo.colors[0]; + } } // Final fallback to white if no background detected