При создании многократно используемых компонентов пользовательского интерфейса (например, значков или кнопок) или поддержке динамических тем может быть сложно обеспечить читаемость текста на непредсказуемом цвете фона. Функция CSS contrast-color() возвращает значение black или white, чтобы обеспечить максимальный коэффициент контрастности с указанным цветом фона.
Определить оптимальный цвет текста
Если у элемента переменный или динамически вставляемый цвет фона, вы можете положиться на браузер, который рассчитает наиболее безопасный цвет текста.
ОБЯЗАТЕЛЬНО. Задайте свойство color с помощью функции contrast-color(), передав цвет фона (или его дополнительный параметр) в качестве аргумента.
.badge {
/* Define the background color as a custom property */
--badge-bg: #e02424;
background-color: var(--badge-bg);
/* MANDATORY: Dynamic contrasting color */
color: contrast-color(var(--badge-bg));
}
НЕПРАВИЛЬНО: использовать contrast-color() для background-color. Он специально разработан для цветов переднего плана (таких как текст или границы), чтобы контрастировать с заданным цветом фона.
Интеграция с темами
Поскольку contrast-color() принимает любое допустимое значение <color>, включая дополнительные параметры CSS, это свойство особенно полезно в системах проектирования. Если вы централизуете фоновые темы в виде переменных, контрастность контента на переднем плане будет автоматически обновляться при изменении темы, даже если цвета заданы пользователем.
РЕКОМЕНДУЕТСЯ. Ссылаться на общие фоновые переменные внутри contrast-color(), чтобы гарантировать синхронизацию в приложении.
.theme-card {
background-color: var(--theme-surface-color);
color: contrast-color(var(--theme-surface-color));
}
.theme-container[data-theme="light"] {
--theme-surface-color: #f4f4f4;
}
.theme-container[data-theme="dark"] {
--theme-surface-color: #1a1a1a;
}
.theme-container[data-theme="custom"] {
--theme-surface-color: var(--user-custom-theme);
}
НЕ ЗАДАВАЙТЕ в коде отдельный цвет текста для каждого состояния взаимодействия, если фон динамический. В противном случае возникнет несоответствие, которое и призван предотвратить атрибут contrast-color().
Резервные стратегии
Чтобы обеспечить поддержку браузеров без contrast-color(), необходимо предоставить резервный вариант. Если цвет фона известен и не меняется, используйте заданный в коде контрастный цвет. Для динамических фонов, цвет которых неизвестен, выберите стратегию из таблицы ниже в зависимости от требований к интерфейсу и поддерживаемых браузеров.
| Стратегия | Контент | Примечания |
|---|---|---|
| Синтаксис относительных цветов | Автоматический расчет контрастности высокого качества только для CSS. | Резервный вариант на основе CSS самого высокого качества. |
| Тень текста | Улучшает читаемость на любом фоне. | Может выглядеть "грязным" или "светящимся", подходит не для всех дизайнов. |
| Контур текста | Сохранение насыщенности шрифта при обеспечении контрастности краев. | Используйте paint-order, чтобы избежать утончения букв, если это возможно. |
| Полупрозрачный оверлей | Обеспечьте минимальную контрастность фона за текстом. | Изменяет цвет фона под текстом. Требуется отдельный текстовый элемент. |
| Фильтры SVG | Контрастность, которая меняется в зависимости от фона. | Требуется отдельный текстовый элемент; реализация не очень удобна. |
Рекомендуется: синтаксис относительного цвета (RCS)
Для браузеров, которые поддерживают RCS, это самый надежный автоматический резервный вариант для динамических цветов.
@supports (color: oklch(from red l c h)) {
.badge {
/* Highest threshold that passes WCAG. Higher values may be more legible. */
--threshold: 0.623;
--l: max(0, sign(var(--threshold) - l));
color: oklch(from var(--badge-bg) var(--l) 0 h);
}
}
@supports (color: contrast-color(red)) {
.badge {
color: contrast-color(var(--badge-bg));
}
}
Резервные ССЦ
Выберите резервный вариант, который лучше всего соответствует вашим ограничениям по дизайну, если RCS недостаточно или не поддерживается.
Вариант 1. Обводка текста
.badge--stroke {
-webkit-text-stroke: 4px black;
}
Вариант 2. Обводка текста с помощью paint-order для сохранения формы букв
.badge--stroke {
-webkit-text-stroke: 4px black;
paint-order: stroke fill;
}
Вариант 3. Полупрозрачный фон
.badge--overlay {
position: relative;
color: #fff;
overflow: hidden;
}
.badge--overlay::before {
content: "";
position: absolute;
inset: 0;
background-color: rgb(0 0 0 / 0.4);
z-index: 0;
}
.badge--overlay span {
position: relative;
z-index: 1;
}
Вариант 4. Тень текста
.badge--shadow {
text-shadow: 0 1px 3px rgb(0 0 0 / 0.8);
}
Вариант 5. Фильтры SVG
Загрузить это определение фильтра SVG. Если вам нужно обеспечить поддержку версий Safari, затронутых этой ошибкой WebKit, которая не позволяет использовать внешние URL и URL данных для фильтров, то код необходимо добавить непосредственно в HTML-документ. В противном случае его следует загрузить из внешнего файла, например SVG, или встроить в CSS.
<!-- Technique from https://miunau.com/posts/dynamic-text-contrast-in-css/ --> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="0" style="display: none;"> <defs> <filter id="contrast-filter" color-interpolation-filters="sRGB"> <feColorMatrix type="matrix" values="0.2126 0.7152 0.0722 0 0 0.2126 0.7152 0.0722 0 0 0.2126 0.7152 0.0722 0 0 0 0 0 1 0"/> <feMorphology operator="dilate" radius="2"/> <feComponentTransfer> <feFuncR type="linear" slope="-255" intercept="128"/> <feFuncG type="linear" slope="-255" intercept="128"/> <feFuncB type="linear" slope="-255" intercept="128"/> </feComponentTransfer> <feComposite operator="in" in2="SourceGraphic"/> </filter> </defs> </svg>Заключите текст в тег
<span>.<div class="badge--svg"> <span>Badge content</span> </div>Примените фильтр к
<span>.
.badge--svg span{
color: var(--badge-bg);
filter: url(#contrast-filter);
}