Страницы

Поиск по вопросам

суббота, 30 ноября 2019 г.

Javascript: найти на странице черный текст на черном фоне

#javascript #jquery #css


Как с помощью Javascript найти на странице все элементы, в которых текст написан
черным цветом по черному фону? При этом черный фон/цвет может быть прописан не у самого
элемента, а у далекого родителя, но после всех наследований в результате получается
черный по черному.

Поставили задачу: сделать на сайте версию для слабовидящих. Один из пунктов - инверсия
цвета, то есть выводим белый текст на черном фоне. Я прописал черный background у body,
поправил css для прочих контейнеров, все хорошо, за исключением одного но. В админке
у некоторых страниц в редакторе WYSIWYG явно прописан черный цвет для текста (в атрибуте
style). В результате этот текст не виден на странице.

Я хочу найти решение, которое позволит решить проблему, не изменяя код страниц.

Например, чтобы javascript автоматически находил такой текст и менял его цвет на
белый. Вопрос в том, как найти такие элементы.

Пока я вижу только вариант рекурсивного прохода по всем элементам DOM с запоминанием
background родителя и проверкой цвета самого элемента.

Но может, есть способ проще, какое-нибудь решение в пару строк на jquery?

Иными словами, нужно добиться, чтобы в примере во втором div > p текст был виден:



.orig {
  background-color: #fff;
}

.invert {
  background-color: #000;
}

Оригинал

Текст

Инверсия

Текст


Ответы

Ответ 1



Пришла в голову мысль, что стили, заданные в редакторе, совсем не обязательно будут задавать тексту черный цвет — это может быть и темно-серый и какой-нибудь коричневый. Текст такого цвета на инвертированном фоне слабовидящим людям будет по-прежнему тяжело прочесть, потому надо определять контрастность текста и фона. Код частично скопипастил с определителя контрастности Лии Веру. Что происходит в этом коде: функция getLuminance() возвращает relative luminance; функция getContrastRatio() возвращает contrast ratio из введенных туда данных о цвете фона и текста. Проходим по каждому параграфу внутри блока .invert, определяем contrast ratio и если он меньше 7 (таково требование WCAG) — делаем текст белым, а если больше 7, то оставляем как есть. UPD: переписал код для определения цвета фона не у родителя, а у самого элемента, для этого надо прописать параграфу в CSS background-color: inherit и переменной bg присваивать значение собственного цвета фона: bg = $(item).css('background-color'). UPD: итоговый вариант, позволяющий делать что угодно с элементами, имеющими недостаточную контрастность и без использования background-color: inherit. Источники: Lea Verou, contrast ratio. Формула подсчёта relative luminance: https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef. Формула подсчета contrast ratio: https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef. $(function() { var color, bg, textLuminance, parentLuminance, cr; $('.invert p').each(function(index, item) { color = $(item).css('color'), bg = $(item).css('background-color'); textLuminance = getLuminance(color); parentLuminance = getLuminance(bg); cr = getContrastRatio(textLuminance, parentLuminance); if(cr <= 7) $(item).css('color', '#fff'); }); function getContrastRatio(l1, l2) { l1 += .05, l2 += .05; var ratio = l1 / l2; if (l2 > l1) { ratio = 1 / ratio; } return ratio = Math.round(ratio, 1); } function getLuminance(color) { var rgb = color.slice(4, -1).split(',').map(Number); for (var i = 0; i < 3; i++) { var rgbI = rgb[i]; rgbI /= 255; rgbI = rgbI < .03928 ? rgbI / 12.92 : Math.pow((rgbI + .055) / 1.055, 2.4); rgb[i] = rgbI; } return .2126 * rgb[0] + .7152 * rgb[1] + 0.0722 * rgb[2]; } }); .orig { background-color: #fff; } .invert { background-color: #000; } .invert p { padding: 5px; background-color: inherit; }

Оригинал

Текст

Инверсия

Обычный текст без инлайновых стилей

Черный Текст

Коричневый Текст

Синий Текст

Желтый Текст

Оранжевый Текст



Ответ 2



Может быть так: $('p').each(function(){ var $this = $(this), wrap = $this.parent('div'), color = $(this).css('color'), bg = wrap.css('backgroundColor'); console.log(color + ' ' + bg); if(color === bg) { $this.css({'color':'#ffffff'}); } }); .orig { background-color: #fff; } .invert { background-color: #000; }

Оригинал

Текст

Инверсия

Текст

либо так: $('p').each(function(){ var $this = $(this), wrap = $this.closest('.invert'), color = $(this).css('color'), bg = wrap.css('backgroundColor'); console.log(color + ' ' + bg); if(color === bg) { $this.css({'color':'#ffffff'}); } }); .orig { background-color: #fff; } .invert { background-color: #000; }

Оригинал

Текст

Инверсия

Текст



Ответ 3



Может с фильтром invert? .orig { background-color: #fff; } .invert { background-color: #000; } .invert p { filter: invert(100%); }

Оригинал

Текст

Инверсия

Текст



Ответ 4



Любопытно. Можно при изменении текстовой ноды (MutationObserver) проверять её цвет, сравнивать его с чёрным и, если слишком тёмный, делать его светлее. При сохранении, обходить дерево (TreeWalker), ставить тексту принудительно цвет.

Ответ 5



Если хотите сделать быстро и просто, то сделайте на нативном CSS с помощью свойства mix-blend-mode: p { color: #fff !important;; mix-blend-mode: difference; }

Оригинал

Текст

Инверсия

Текст

mix-blend-mode

Текст



Комментариев нет:

Отправить комментарий