How to calculate the contrast ratio of two colors

Picking colors for elements on a website is not merely an aesthetic detail, it also matters for accessibility. After I introduced a dark mode for the website, Tosh kindly provided feedback with regard to the color choices I made, or as in this case more importantly did not make.

In light mode, I go with the user-agent styles for the links, and there the contrast ratio is fine, but the same choice in dark mode, was under the level of what the W3C Web content accesibility guidelines recommend.

My go-to resource for figuring out the right colors with regard to the WCAG is the WebAIM contrast checker.

What up until now I haven't understood was how these figures are actually calculated. And it is actually all laid out in pseudocode in the WCAG recommendation. But since it is spread out, I decided to write it up for my personal reference.

So, the spec defines the constrast ratio as

(L1 + 0.05) / (L2 + 0.05), where L1 is the relative luminance of the lighter of the colors, and L2 is the relative luminance of the darker of the colors.
Which leads to two more questions: What is the relative luminance and how do you know which color is the lighter one?

To answer the latter: the lighter color is the one with the higher relative luminance. And to answer the former, I quote the definition from the WACG again: The relative luminance is the relative brightness of any point in a colorspace, normalized to 0 for darkest black and 1 for lightest white.

But how do I get to this number between 0 and 1? Well, by simply reading on in the spec. There is some some pseudo code, which is easily translatable to Javascript (which I'm doing here in form of a literate program again):

Now, the contrast ratio is easy to implement:

An input type color will return a string in the form "#RRGGBB". To use this as an input for the color parameters of the contrastRatio function I need another utility function.

So now I can drop in two color pickers: and to cobble everything together:

The contrast ratio of the chosen colors is : 1

Coming back to the starting point, color contrast is only one aspect with regard to what affordances links should provide, but that is a topic for a different blog post.