Вот буквально вчера делал с помощью js.
Алгоритм простой:
1. Взять цвет фона
2. Перевести hex в hsl
3. Если l в hsl выше 0.8 (то есть, фон яркий), берем из hsl параметр hue (оттенок), берем насыщенность 100% и яркость 10%, и конвертируем новый темный оттенок обратно в hex
4. Применяем этот hex к тексту
Таким образом мы имеем либо белый текст на темном фоне (по-умолчанию), либо темный текст, слегка подкрашенный в оттенок фона, на светлом фоне. Почему подкрашенный? Потому что чистый черный на условно светло-розовом будет смотреться плохо. А вот слегка розоватый — отлично.