(function () { "use strict"; function parseColor(colorStr) { const div = document.createElement("div"); div.style.color = colorStr; document.body.appendChild(div); const computedColor = getComputedStyle(div).color; document.body.removeChild(div); const rgbaMatch = computedColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)/); if (!rgbaMatch) return [0, 0, 0]; const r = parseInt(rgbaMatch[1], 10); const g = parseInt(rgbaMatch[2], 10); const b = parseInt(rgbaMatch[3], 10); return [r, g, b]; } function rgbToHsl(r, g, b) { r /= 255; g /= 255; b /= 255; const max = Math.max(r, g, b), min = Math.min(r, g, b), delta = max - min; let h = 0, s = max === 0 ? 0 : delta / (max + min), l = (max + min) / 2; if (delta !== 0) { switch (max) { case r: h = (g - b) / delta + (g < b ? 6 : 0); break; case g: h = (b - r) / delta + 2; break; case b: h = (r - g) / delta + 4; break; } h *= 60; } return [ Math.round(h), Math.round(s * 100), Math.round(l * 100) ]; } function isLightBackground(rgb) { const [r, g, b] = rgb; const brightness = (r * 299 + g * 587 + b * 114) / 1000; return brightness > 190; } function getBgColor(element) { let currentElement = element; while (currentElement && currentElement !== document.body) { const bg = getComputedStyle(currentElement).backgroundColor; if (bg && bg !== "rgba(0, 0, 0, 0)" && bg !== "transparent") { return parseColor(bg); } currentElement = currentElement.parentElement; } return [255, 255, 255]; // fallback — белый фон } function getColorValues(el) { const fg = getComputedStyle(el).color; return { foregroundColor: parseColor(fg), backgroundColor: getBgColor(el) }; } const SELECTOR = "font[color]"; const THRESHOLD = 4.5; const LIGHTEN = 20; const DESATURATE = 20; const elements = document.querySelectorAll(SELECTOR); let index = 0; function processBatch() { const batchSize = 5; // обрабатываем всего 5 элементов за раз for (let i = 0; i < batchSize && index < elements.length; i++, index++) { const el = elements[index]; if (el.dataset.colorAdjusted === "true") continue; const {foregroundColor, backgroundColor} = getColorValues(el); if (isLightBackground(backgroundColor)) { el.dataset.colorAdjusted = "true"; continue; } const contrastRatio = (function getContrastRatio(rgb1, rgb2) { const lum1 = (0.2126 * rgb1[0] + 0.7152 * rgb1[1] + 0.0722 * rgb1[2]) / 255; const lum2 = (0.2126 * rgb2[0] + 0.7152 * rgb2[1] + 0.0722 * rgb2[2]) / 255; return lum1 > lum2 ? (lum1 + 0.05) / (lum2 + 0.05) : (lum2 + 0.05) / (lum1 + 0.05); })(foregroundColor, backgroundColor); if (contrastRatio < THRESHOLD) { const [r, g, b] = foregroundColor; let hsl = rgbToHsl(r, g, b); const adjustmentFactor = Math.max(0, (THRESHOLD - contrastRatio) / THRESHOLD); hsl[1] = Math.max(0, hsl[1] - DESATURATE * adjustmentFactor); let brightnessIncrease = 0; if (contrastRatio < 0.7 * THRESHOLD) { brightnessIncrease = 3 * LIGHTEN; } else if (contrastRatio < THRESHOLD) { brightnessIncrease = 0.5 * LIGHTEN; } hsl[2] = Math.min(100, hsl[2] + brightnessIncrease * adjustmentFactor); el.style.color = `hsl(${hsl[0]}, ${hsl[1]}%, ${hsl[2]}%)`; el.dataset.colorAdjusted = "true"; } } if (index < elements.length) { setTimeout(processBatch, 0); } } console.time("Adjust colors"); processBatch(); console.timeEnd("Adjust colors"); })(); |