Dark Mode Color Contrast Checker
--
Ensure your dark mode colors meet WCAG contrast requirements. Run this in dev tools to check all text colors.
function getContrastRatio(color1, color2) { // Convert hex to RGB function hexToRgb(hex) { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16), } : null; }
// Get relative luminance function getLuminance(r, g, b) { const [rs, gs, bs] = [r, g, b].map((c) => { c = c / 255; return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4); }); return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs; }
const rgb1 = hexToRgb(color1); const rgb2 = hexToRgb(color2);
if (!rgb1 || !rgb2) return null;
const lum1 = getLuminance(rgb1.r, rgb1.g, rgb1.b); const lum2 = getLuminance(rgb2.r, rgb2.g, rgb2.b);
const brightest = Math.max(lum1, lum2); const darkest = Math.min(lum1, lum2);
return (brightest + 0.05) / (darkest + 0.05);}
function checkDarkModeContrast() { // Force dark mode document.documentElement.classList.add('dark');
const results = [];
// Check all text elements const textElements = document.querySelectorAll('p, h1, h2, h3, h4, h5, h6, span, a, li');
textElements.forEach((el) => { const styles = window.getComputedStyle(el); const color = styles.color; const bgColor = styles.backgroundColor;
// Convert RGB to hex function rgbToHex(rgb) { const match = rgb.match(/\d+/g); if (!match) return null; const [r, g, b] = match.map(Number); return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); }
const colorHex = rgbToHex(color); const bgColorHex = rgbToHex(bgColor);
if (colorHex && bgColorHex) { const ratio = getContrastRatio(colorHex, bgColorHex);
if (ratio && ratio < 4.5) { results.push({ element: el.tagName.toLowerCase(), text: el.textContent?.slice(0, 50), color: colorHex, bgColor: bgColorHex, ratio: ratio.toFixed(2), passes: false, }); } } });
console.log('🌙 Dark Mode Contrast Report\n');
if (results.length === 0) { console.log('✅ All text meets WCAG AA contrast requirements (4.5:1)'); } else { console.log(`❌ Found ${results.length} contrast issues:\n`);
console.table( results.map((r) => ({ Element: r.element, Text: r.text, Color: r.color, 'BG Color': r.bgColor, 'Ratio': r.ratio, 'Required': '4.5:1', })) );
console.log('\n💡 Recommended fixes:'); results.slice(0, 5).forEach((r) => { console.log(`\n${r.element} { color: ${r.color} } on { background: ${r.bgColor} }`); console.log(`Current ratio: ${r.ratio}:1 (needs 4.5:1)`); console.log('Try increasing lightness or using a different shade'); }); }}
// Run the checkercheckDarkModeContrast();Usage:
- Open dev tools console
- Paste the script
- Review the report
Example output:
🌙 Dark Mode Contrast Report
❌ Found 3 contrast issues:
┌─────────┬──────────────┬─────────┬───────────┬───────┬──────────┐│ Element │ Text │ Color │ BG Color │ Ratio │ Required │├─────────┼──────────────┼─────────┼───────────┼───────┼──────────┤│ p │ Some text... │ #6B7280 │ #111111 │ 3.2 │ 4.5:1 ││ a │ Click here │ #60A5FA │ #1F2937 │ 4.1 │ 4.5:1 ││ span │ Label text │ #9CA3AF │ #000000 │ 4.3 │ 4.5:1 │└─────────┴──────────────┴─────────┴───────────┴───────┴──────────┘
💡 Recommended fixes:
p { color: #6B7280 } on { background: #111111 }Current ratio: 3.2:1 (needs 4.5:1)Try increasing lightness or using a different shadeTailwind fix:
<!-- ❌ Fails contrast (3.2:1) --><p class="text-zinc-500 dark:text-zinc-500">Text</p>
<!-- ✅ Passes contrast (5.1:1) --><p class="text-zinc-500 dark:text-zinc-300">Text</p>Automated testing:
// In your test suiteexpect(getContrastRatio('#FFFFFF', '#000000')).toBeGreaterThan(4.5);When to use:
- Before deploying dark mode
- After color scheme changes
- Accessibility audits
- Ensuring WCAG compliance