Got a problem I'm not sure how to approach.

I'm being given a string of text with indeterminate length, around typical "body text" size. The text is a solid color, and the background can be a solid OR a gradient of one or more colors of varying luminance. The goal is to make the text readable across the entire background while adjusting the color channels as little as possible.

How could I find the SMALLEST possible color adjustments to the foreground and/or background that would make the text readable, according to WCA standards or others?

New contributor
Cliff is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
  • $\begingroup$ Perhaps you can edit the question to summarize the WCA standard's definition of what combinations are readable? Can that be made precise / formalized, or is it subjective? $\endgroup$ – D.W. May 4 at 23:03
  • $\begingroup$ @D.W. edited with a link! $\endgroup$ – Cliff May 4 at 23:38
  • 2
    $\begingroup$ Can I ask you please to formalize the problem in the question? It's not clear how large "body text size" is (especially since we care more about image size compared with the number of characters in the string), what exactly "gradient of one or more colors of varying luminance" means, exactly which part of your link you care about, what the contrast ratio is (citing Wikipedia, "There is no official, standardized way to measure contrast ratio"), what kind of modifications we are allowed to do (e.g. should it still be gradient or solid). I.e. please make the question self-contained. $\endgroup$ – Dmitry May 5 at 5:21

The text has a luminance value $t_0$ and the background occupies a luminance interval $[L_0,H_0]$, $L_0 \le H_0$. I think what you want is to ensure a separation of at least some $s$ between them. There are many degrees of freedom here; one way to capture most of them is to decide beforehand on a way to penalise changes in these variables, as well as the penalty for changing the background interval width $H-L$, and then look for a solution that minimises this penalty cost.

We could use a linear cost model, where the absolute value of the change in each variable is penalised, but this has the disadvantage that optimal solutions are not always unique. So let's use a quadratic cost model (least squares), with penalty weights $c_t, c_L$ and $c_H$ for changes to the main variables, and also a weight $c_d$ for the penalty for changing $H-L$ (i.e., stretching or squashing the background luminance range). Then you want to choose $t, L$ and $H$ to minimise $$p = c_t(t-t_0)^2 + c_L(L-L_0)^2 + c_H(H-H_0)^2 + c_d(H-L-H_0+L_0)^2$$ such that $L \le H$ and either $t \ge H + s$ or $t \le L - s$. This gives a lot of flexibility: Set any of the $c$-parameters to zero to express that you don't care about changes in the corresponding quantity; set it extremely high to try hard to avoid changing it. A sensible first choice might be to set them all equal to 1, and if that yields solutions that "look wrong", increase the weights of whichever values moved around too much.

If $t_0$ is already separated from $[L_0, H_0]$ by $s$, then leaving it unchanged is the optimal solution. Otherwise, intuitively, an optimal solution must have a tight gap, i.e., either $t = H+s$ or $t = L-s$. This can be solved by solving for each of the two cases separately and choosing the better one.

To solve for the first case, substitute $t = H+s$, find the partial derivatives of $p$ w.r.t. the two remaining variables $H$ and $L$, set these to zero:

$$\begin{align} p & = c_t(H+s-t_0)^2 + c_L(L-L_0)^2 + c_H(H-H_0)^2 + c_d(H-L-H_0+L_0)^2\\ \frac{\partial p}{\partial L} & = 2c_L(L-L_0) + 2c_d(H-L-H_0+L_0) = 0\\ \frac{\partial p}{\partial H} & = 2c_t(H+s-t_0) + 2c_H(H-H_0) + 2c_d(H-L-H_0+L_0) = 0 \end{align}$$, and solve the resulting set of simultaneous equations for these variables to find the minimum:

$$\begin{align} L & = \frac{c_LL_0 + c_d(H_0-H-L_0)}{c_L - c_d}\\ H & = \frac{c_t(t_0-s) + c_HH_0 + c_d(L+H_0-L_0)}{c_t + c_H + c_d}\\ & = \frac{c_t(t_0-s) + c_HH_0 + c_d(\frac{c_LL_0 + c_d(H_0-H-L_0)}{c_L - c_d}+H_0-L_0)}{c_t + c_H + c_d} \end{align}$$

Having computed the optimal value of $H$, you can substitute this back into the expressions for $L$ and $t$, and then calculate $p$ for this case. The derivation for the $t=L-s$ case is very similar. Finally, pick whichever gives the lower $p$ value.

  • $\begingroup$ I haven't dealt with calculus in years but this looks promising. Many thanks. $\endgroup$ – Cliff May 6 at 16:34
  • $\begingroup$ You're welcome :) $\endgroup$ – j_random_hacker 2 days ago

Your Answer

Cliff is a new contributor. Be nice, and check out our Code of Conduct.

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.