When technology meets theory: How to make color schemes accessible with VueJS

Krystal Campioni
Jun 11, 2019 · 5 min read
Image for post
Image for post

I've been studying a lot about web accessibility lately, and I noticed that one of the aspects that's often overlooked is color contrast. It’s particularly hard to prevent contrast issues in apps that allow the user to select the color scheme.

Many times, I’ve been in situations where there were real tugs-of-war between designers and accessibility experts. One side pushing for high contrast and the other pushing for beauty.

This got me thinking: there has to be a win-win solution

Image for post
Image for post

Some years ago, I wrote an article explaining how to create color harmonies with sass. What if I could use a similar approach to create a proof of concept? How can we allow the user to select a UI color scheme making sure that the colors have enough contrast?

This is what I managed to implement in the end:

Image for post
Image for post
You can play around with this prototype here: https://krystalcampioni.github.io/accessible-color-schemes/

Ok, so how does it work?

In the right panel, we have a form with a couple of inputs that allow the user to select a main color, a mode and a color scheme.

Dealing with color manipulation in Javascript can be tricky, so we can use the NPM package Color.

We should also save a MIN_CONTRAST so we can use it afterwards. According to the Web Content Accessibility Guidelines (WCAG) the contrast should be at least 4.5

If you’re not sure how this works, the way we manipulate colors today is based on the initial studies of color theory. By selecting one initial color in the wheel, we can rotate X degrees to get to another. And create harmonies based a formula, or color scheme:

Image for post
Image for post
In this example, the white lines show the selected colors

With that in mind, we can create the markup for the form that will allow the user to manipulate the UI, starting with an input for the main color:

By including the type=”color” in the input, we have access to the browser’s color picker. We can then use a v-model=”mainColor” to save the user input in our data object. Then, we can trigger an updateColors method every time the value changes.

Next, we have some radio inputs that allow the user to select the colorScheme:

Every time the user selects a different color scheme, we point to a new object inside the colorSchemes object. Each color scheme contains its name and 3 angles:

Considering that the color scheme will always have 4 color slots. We can use one mainColor ( selected by the user ) + 3 colors based on the angles of the selected color scheme.

You’ll notice that in the example above, some angles have repeated numbers. This is so we can fill in the 4 slots even for schemes that contain fewer colors. The Complementary scheme, for instance contains colors that sit across from each other on the wheel. so we would only have the initial color ( or that color rotated by 0° ) and another one, rotating the initial color by 180°.

Once we have a mainColor and the angles in the selectedColorScheme, we can use the Color package in computed properties to automatically get the secondary, tertiary and quaternary colors:

What we've talked about so far allows the user to select color schemes, but to make sure that they are accessible, we should test for color contrast between the background and text.

So instead of considering just one color for each slot, we should consider two colors per slot: one for the background and one for the text.

By refactoring the updateColors method, we can generate both text and background colors as welll as check the contrast. Then, we can update the CSS:

the generateTextAndBg method will return an object with both text and background colors, after achieving a combination that has enough contrast:

With this approach, we can guarantee enough contrast by using black or white text. But what if we wanted something a bit different?

We can use the original color and darken/lighten it until we have enough contrast instead of just using black and white:

Image for post
Image for post

If we know that in our UI, we have certain constraints, we can use that in our favor to implement dynamic colors easily. In the prototype we created for instance, product cards always have white backgrounds with some dark gray text and a link . Since we want the links to be visually distinguished from the other text information, and we know it's always going to be on a white background, we can generate the link colors based on the quaternary color available.

By using the quaternary for links, we guarantee that the link color is always going to be different from the main color, no matter if the scheme selected has repeating slots or not.

Image for post
Image for post

Another example of useful design constraints is toggling between dark and light mode. We can watch for changes on the mode selection, and use hardcoded text and background color values:

Image for post
Image for post

In this prototype, you'll notice that the banner image colors also change depending on what the user selected:

Image for post
Image for post

To achieve this, we simply use an element covering the banner image, that has .4 opacity and a linear-grading from the tertiary to the quaternary colors:

This example is far from perfect, but hopefully some of the techniques explored here will help us build more accessible interfaces.

The code for the prototype is on github, feel free to contribute to it either by submitting a pull request or suggesting any changes :
https://github.com/krystalcampioni/accessible-color-schemes

Vue.js Developers

Helping web professionals up their skill and knowledge of…

Krystal Campioni

Written by

Senior Front-end developer @ Shopify. Giphy and Whale fluent speaker. Tech, design, and marine life enthusiast | www.krystalcampioni.com

Vue.js Developers

Helping web professionals up their skill and knowledge of Vue.js

Krystal Campioni

Written by

Senior Front-end developer @ Shopify. Giphy and Whale fluent speaker. Tech, design, and marine life enthusiast | www.krystalcampioni.com

Vue.js Developers

Helping web professionals up their skill and knowledge of Vue.js

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store