- Issue created by @rkoller
- 🇨🇦Canada mgifford Ottawa, Ontario
There are 11 Accent colors, 4 different Focus colors, plus Dark/Light modes. That's a lot of combinations. Probably too many combinations to be able to provide good guidance.
Drupal Core should be providing a good example. We have as a community committed to striving to meet WCAG 2.2 AA standards. This is especially true of Core and Drupal CMS.
#0750E6 / #FFF
#2E6DD0 / #FFF
#4300BF / #FFF
#5B00FF / #FFF
#0F857F / #FFF - Fail (could we not just use #088488)
#00875F / #FFF
#D12E70 / #FFF
#D8002E / #FFF
#DA6303 / #FFF - Fail (Could we not just use #B56026)
#111111 / #FFF - 🇩🇪Germany rkoller Nürnberg, Germany
? this issue is about adding color contrast checks for the color chosen in the custom color widget (against all relevant colors depending if the light or dark mode is chosen)
and what are those color combinations of yours refer to? focus colors accents colors? all the combinations are covered in the google sheets.
- 🇨🇦Canada mgifford Ottawa, Ontario
Ya, I think I filed this in the wrong place. I can move it, but what is the issue.
- 🇩🇪Germany rkoller Nürnberg, Germany
as i'Ve said all the combinations are already listed in the google sheet.
focus:
https://docs.google.com/spreadsheets/d/1won35PxhRFexJYE8FmZ4DCNTo7xEAxC8...accent colors:
https://docs.google.com/spreadsheets/d/1won35PxhRFexJYE8FmZ4DCNTo7xEAxC8... (and the components tab contains all the components from the rest of the issues)and it is a bit more complex since it is not just a single background color but several for light and several for dark mode plus the colors are semi transparent and for the focus outline you have two colors due to the fact how the focus is currently built in gin.
- 🇨🇦Canada mgifford Ottawa, Ontario
I suspect that some JS like this will be needed:
(function () { const MIN_CONTRAST = 4.5; const BACKGROUNDS = [ { hex: '#ffffff', name: 'white' }, { hex: '#2A2A2D', name: 'dark grey' } ]; const fields = [ { inputId: 'edit-accent-color', warningId: 'accent-warning', }, { inputId: 'edit-focus-color', warningId: 'focus-warning', }, ]; function hexToRgb(hex) { const val = hex.replace('#', ''); return { r: parseInt(val.slice(0, 2), 16) / 255, g: parseInt(val.slice(2, 4), 16) / 255, b: parseInt(val.slice(4, 6), 16) / 255, }; } function luminance({ r, g, b }) { const adjust = (c) => c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4); return ( 0.2126 * adjust(r) + 0.7152 * adjust(g) + 0.0722 * adjust(b) ); } function contrastRatio(l1, l2) { const [a, b] = [l1, l2].sort((x, y) => y - x); return (a + 0.05) / (b + 0.05); } function updateWarning(field) { const input = document.getElementById(field.inputId); const existing = document.getElementById(field.warningId); if (existing) existing.remove(); const val = input.value; if (!/^#[0-9a-fA-F]{6}$/.test(val)) return; const fgLum = luminance(hexToRgb(val)); const fails = BACKGROUNDS.filter((bg) => { const bgLum = luminance(hexToRgb(bg.hex)); return contrastRatio(fgLum, bgLum) < MIN_CONTRAST; }); if (fails.length) { const msg = document.createElement('div'); msg.id = field.warningId; msg.style.color = 'red'; msg.style.marginTop = '0.25rem'; msg.textContent = '⚠️ Low contrast against: ' + fails.map((f) => f.name).join(', ') + ` (min ${MIN_CONTRAST}:1)`; input.parentNode.appendChild(msg); } } document.addEventListener('DOMContentLoaded', () => { fields.forEach((field) => { const input = document.getElementById(field.inputId); if (input) { input.addEventListener('input', () => updateWarning(field)); updateWarning(field); // initial check } }); }); })();