Handle Accessible Design System Themes With CSS Coloration-Distinction()

There’s definitely no scarcity of design techniques out there to make use of when constructing your subsequent venture. Between IBM’s Carbon, Wanda and Nord, there are many terrific design techniques to select from. But, whereas every one comprises its personal nuances and opinions, most share an identical aim — simplifying the event course of of making superbly accessible person interfaces.

It’s an admirable aim and, truthfully, one which has led me to shift my very own profession into design techniques. However a core characteristic on the basis of many design techniques is the extensibility for theming. And why wouldn’t it’s? With out some flexibility for branding, each product utilizing a selected system would look the identical, à la Bootstrap round 2012.

Whereas offering help for customized themes is important, it additionally leaves probably the most well-intentioned system’s accessibility on the mercy of the implementation. Some groups could spend weeks, if not months, defining their ultimate shade palette for a rebranding. They’ll labor over every shade and shade mixture to make sure the whole lot is dependable, informative, and accessible.

Others merely can’t and/or received’t try this.

It’s one factor to require alt textual content on an img component or a label for an enter component, however imposing accessible shade palettes is a wholly totally different beast. It’s a beast with jagged yellow tooth, fiery-red eyes, and inexperienced scales protecting its physique like sheets of crocodile armor.

At the very least you suppose it’s. For all you understand, it might be a beast of nothing greater than vague shades of black and barely darker black.

And therein lies the issue.

The CSS Coloration-Distinction() Operate

Constructing inclusive merchandise doesn’t imply supporting gadgets however supporting the folks utilizing them.

The CSS color-contrast() operate is an experimental characteristic which is presently part of Color Module 5. Its objective — and the rationale for the joy of this text — is to pick out the best contrasting shade from a listing compared in opposition to a base shade.

For the sake of this text, we are going to consult with the primary parameter because the “base shade” and the second because the “shade record.” These parameters can settle for any mixture of browser-supported CSS shade codecs, however be weary of opacities. There’s an elective third parameter, however let’s have a look at that later. First, let’s outline what we imply by this being an experimental characteristic.

On the time of writing, the color-contrast() characteristic is barely out there within the Safari Technology Preview browser. The characteristic may be toggled by the Develop and Experimental Options menus. The next demos will solely work if the characteristic is enabled in that browser. So, when you’d like to change, now wouldn’t be the worst time to take action.

Now, with the bottom syntax, terminology, and help out of the best way, let’s dive in. 🤿

Coloration Me Intrigued

It was Rachel Andrew’s discuss at AxeCon 2022, “New CSS With Accessibility in Mind”, the place I used to be launched to color-contrast(). I scribbled the operate down into my pocket book and circled it a number of instances to make it pop. As a result of my thoughts has been fully on the earth of design techniques as of late, I puzzled how large of an impression this little CSS characteristic might have in that context.

In her presentation, Rachel demoed the new feature by dynamically defining textual content colours primarily based on a background. So, let’s begin there as nicely, by setting background and textual content colours on an article.

article {
  --article-bg: #222;

  background: var(--article-bg);
  shade: color-contrast(var(--article-bg) vs #FFF, #000);

We begin by defining the --article-bg customized property as a darkish gray, #222. That property is then used as the bottom shade within the color-contrast() operate and in contrast in opposition to every merchandise within the shade record to search out the best contrasting worth.

Base Coloration Coloration Checklist Distinction Ratio
#222 #FFF 15.9
#222 #000 1.31

Consequently, the article’s shade shall be set to white, #FFF.

However this may be taken additional.

We will successfully chain color-contrast() capabilities by utilizing the results of one as the bottom shade of one other. Let’s lengthen the article instance by defining the ::choice shade relative to its textual content.

article {
  --article-bg: #222;
  --article-color: color-contrast(var(--article-bg) vs #FFF, #000);

  background: var(--article-bg);
  shade: var(--article-color);

  ::choice {
    background: color-contrast(var(--article-color) vs #FFF, #000);

Now, because the textual content shade is outlined, so will its choice background.

The elective third parameter for color-contrast() defines a goal distinction ratio. The parameter accepts both a key phrase — AA, AA-large, AAA, and AAA-large — or a quantity. When a goal distinction is outlined, the primary shade from the colour record that meets or exceeds it’s chosen.

That is the place color-contrast() might actually empower design techniques to implement a particular degree of accessibility.

Let’s break this down.

.dark-mode {
  --bg: #000;
  --color-list: #111, #222;

.dark-mode {
  background: var(--bg);
  shade: color-contrast(var(--bg) vs var(--color-list));

  &.with-target {
    shade: color-contrast(var(--bg) vs var(--color-list) to AA);

The magic right here occurs when the 2 shade declarations are in contrast.

The bottom .dark-mode class doesn’t use a goal distinction. This ends in the shade being outlined as #222, the best contrasting worth from the colour record relative to its base shade of black. For sure, the distinction ratio of 1.35 could be the highest, nevertheless it’s removed from accessible.

Examine this to when the .dark-mode and .with-target lessons are mixed, and a goal distinction is specified. Regardless of utilizing the identical base shade and shade record, the result’s a lot totally different. When no worth within the shade record meets the AA (4.5) goal distinction, the operate selects a price that does. On this case, white.

That is the place the potential of color-contrast() is the brightest.

Within the context of design techniques, this is able to enable a system to implement a degree of shade accessibility with very granular management. That degree is also a :root-scoped customized property permitting the goal distinction to be dynamic but world. There’s an actual feeling of management on the product aspect, however that comes at a price through the implementation.

There’s a logical disconnect between the code and the outcome. The code doesn’t talk that the colour white would be the outcome. And, after all, that management on the product aspect interprets to uncertainty with the implementation. If an individual is utilizing a design system and passes particular colours into their theme, why are black and white getting used as an alternative?

The primary concern might be remedied by understanding the color-contrast() characteristic extra deeply, and the second might be alleviated by clear, communicative documentation. Nevertheless, in each instances, this shifts the burden of expectation onto the implementation aspect, which isn’t ultimate.

In some instances, the express management will justify the prices. Nevertheless, there are different drawbacks to color-contrast() that may have to be thought of in all instances.

Not All That Glitters Is Gold

There are inevitable drawbacks to contemplate, as with every experimental or new characteristic, and color-contrast() isn’t any totally different.

Coloration And Visible Contrasts Are Completely different Issues

When utilizing color-contrast() to find out textual content shade primarily based on its background, the operate is evaluating precisely that — the colours. What color-contrast() doesn’t consider are different types which will have an effect on visible distinction, comparable to font measurement, weight, and opacity.

This implies it’s potential to have a shade pairing that technically meets a particular distinction threshold however nonetheless ends in an inaccessible textual content as a result of its measurement is just too small, weight is just too mild, or its opacity is just too clear.

To be taught extra about accessible typography, I extremely advocate Carie Fisher’s discuss, “Accessible Typography Essentials.”

Customized Properties And Fallbacks

Since CSS customized properties help fallback values for when the property isn’t outlined, it appeared like a great strategy to make use of color-contrast() as a progressive enhancement.

--article-color: color-contrast(#000 vs #333, #FFF);
shade: var(--article-color, var(--fallback-color));

If color-contrast() isn’t supported, the --article-color property wouldn’t be outlined, and due to this fact the --fallback-color could be used. Sadly, that’s not how this works.

An attention-grabbing factor occurs in unsupported browsers — the customized property could be outlined with the operate itself. Right here’s an instance of this from Chrome DevTools:

As a result of the --article-color property is technically outlined, the fallback received’t set off.

Nevertheless, that’s to not say color-contrast() can’t be used progressively, although. It may be paired with the @helps() operate, however be aware when you determine to take action. As thrilling as it might be, with such restricted help and potential for syntax and/or performance adjustments, it might be greatest to carry off on sprinkling this little gem all through a whole codebase.

@helps (shade: color-contrast(#000 vs #fff, #eee)) {
  --article-color: color-contrast(var(--article-color) vs #fff, #000);

The Highest Distinction Doesn’t Imply Accessible Distinction

Regardless of the management color-contrast() can supply with colours and themes, there are nonetheless limitations. When the operate compares the bottom shade in opposition to the record and no goal distinction is specified, it would choose the best contrasting worth. Simply because the 2 colours supply the best distinction ratio, it doesn’t imply it’s an accessible one.

h1 {
  background: #000;
  shade: color-contrast(#000 vs #111, #222);

On this instance, the background shade of black. #000 is in contrast in opposition to two shades of darkish gray. Whereas #222 could be chosen for having the “biggest” distinction ratio, pairing it with black could be something however nice.

No Gradient Assist

In hindsight, it was possibly a contact formidable making an attempt gradients with color-contrast(). Nonetheless, by some testing, it appears gradients are usually not supported. Which, as soon as I considered it, is sensible.

If a gradient transitioned from black to white, what would the bottom shade be? And wouldn’t it have to be relative to the place of the content material? It’s not just like the operate can interpret the UI. Nevertheless, Michelle Barker has experimented with using CSS color-mix() and color-contrast() together to help this actual use case.

It’s not you, color-contrast(), it’s me. Effectively, it’s really the gradients, however you understand what I imply.

Wrapping Up

That was quite a lot of code and demos, so let’s take a step again and assessment color-contrast().

The operate compares a base shade in opposition to a shade record, then selects the best contrasting worth. Moreover, it will possibly evaluate these values in opposition to a goal distinction ratio and both choose the primary shade to fulfill that threshold or use a dynamic shade that does. Pair this with progressive enhancement, and we’ve bought a characteristic that may drastically enhance net accessibility.

I consider there are nonetheless loads of unexplored areas and use instances for color-contrast(), so I need to finish this text with some further ideas and/or questions.

How do you see this characteristic being leveraged when working with totally different shade modes, like mild, darkish, and excessive distinction? May a React-based design system expose an elective targetContrast prop on its ThemeProvider as a way to implement accessibility if the theme falls brief? Would there be a use case for the operate to return the bottom contrasting worth as an alternative? If there have been two base colours, might the operate be used to search out the most effective contrasting worth between them?

What do you suppose?


Additional Studying on Smashing Journal


Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

We use cookies to give you the best experience. Cookie Policy