Cory Rylan

My name is , Google Developer Expert, Speaker, Software Developer. Building Design Systems and Web Components.

Follow @coryrylan
CSS

CSS Interaction Theming with Accent Color and Color Contrast

Cory Rylan

- 4 minutes

Theming in CSS has improved quite a bit in the past few years. CSS Custom Properties introduced true dynamic theming to the Web. New features recently have shipped or are being proposed that can take theming even further.

Features such as color-scheme allow us or the user to define preferences such as dark themes or high contrast modes in the browser. This immediately improves the default native controls when switching to color-scheme: dark.

chrome color scheme light chrome color scheme dark

The accent-color property makes color customizations across native controls easy and with only one line of CSS. The benefit of accent-color is the browser can automatically generate the various color states and contrasts based on the single color provided. This ensures a consistent and accessible experience for users and reduces a lot of custom CSS from having to be created.

chrome accent color light chrome accent color dark

Now while accent-color and color-scheme helps customize native controls easier, it doesn't help us with custom components or elements we want to customize, like buttons.

Typically, when styling interaction states on buttons, we adjust the element's background color based on the state.

button {
background: gray;
}

button:hover {
background: lightgray;
}

button:hover {
background: darkgray;
}

Reassigning the background colors, however, introduces a lot of maintenance. In addition, for each color of an interactive element, we have several potential interaction states, default, hover, active, selected, and disabled. Then if we add theming, this further complicates the number of color values we have to define.

Secondary Background Color with CSS Background Image

Leveraging the CSS background-image property, we can create a "secondary" background color that we can adjust based on the current state.

button {
background: blue;
background-image: linear-gradient(hsla(0, 0%, 0%, 0.5) 0 0);
}

Using HSLA, we can adjust the alpha value of either black to darken or white to lighten the background color. The benefit to this over CSS filter/brighten is that it only changes the background color and preserves the original text color.

button:hover {
background-image: linear-gradient(hsla(0, 0%, 0%, 0.1) 0 0);
}

button:active {
background-image: linear-gradient(hsla(0, 100%, 100%, 0.1) 0 0);
}
adjusting interaction colors with css background image

With the CSS background-image we can easily adjust the "interaction" layer without redefining new colors. We can abstract this into a more generic solution via CSS Custom Properties.

:root {
--interaction: 0;
--interaction-hover: 0.1;
--interaction-active: 0.1;
}

[interaction] {
background-image: linear-gradient(hsla(0, 0%, 0%, var(--interaction)) 0 0);
}

[interaction]:hover {
background-image: linear-gradient(hsla(0, 0%, 0%, var(--interaction-hover)) 0 0);
}

[interaction]:active {
background-image: linear-gradient(hsla(0, 100%, 100%, var(--interaction-active)) 0 0);
}

Now we can adjust our accent color and alpha value with CSS custom properties and automatically create new visual interaction states.

CSS Color Contrast

We can dynamically change the background color now with our interactions; however, this only partially fixes some of the issues. For example, if our background color is too light, we may lose the contrast needed for our text.

low contrast css interaction

Notice in Chrome, the checkmark is now dark relative to the background green of our checkbox. When using the CSS accent-color the browser will automatically switch the text/foreground color to the appropriate contrast. However, for our button, the contrast is broken. Unfortunately, there has yet to be an easy cross-browser solution for this. Luckily there is a new CSS spec, color-contrast which can provide this automatic contrast checking.

button {
color: color-contrast(#5fca49 vs #fff, #000);
}

The color-contrast function takes a base color and a list of color values to compare. The browser will determine which color provides the appropriate contrast for the background and assign that color. This feature gives us the native functionality that browsers internally have today.

With Safari Technical Preview, you can enable CSS color-contrast behind the experimental flag.

safari color contrast light safari color contrast dark

Now with any accent color, we choose the text color that will automatically adjust to the best contrast level.

With accent-color and hopefully the adoption of color-contrast automatic and configurable interactions, styles are making themeing in CSS easier than ever. Hopefully, future API proposals will enable us to leverage the internals of the accent-color feature for custom elements without the need for workarounds like background-image. Check out the full demo below!

View Demo Code   
 

No spam. Short occasional updates on Web Development articles, videos, and new courses in your inbox.

Related Posts

Web Components

Style States with Web Components and CSS Custom Properties

Learn how to leverage CSS Custom Properties to make our Web Component styles easy to understand and maintain with multi-state components.

Read Article
CSS

Converting CSS Pixels to Rems

Learn how to convert CSS pixel values to rem to provide scalable typography features and improve accessibility with page zoom.

Read Article
Web Components

Simple CSS Custom Property APIs with Web Components

Learn how CSS Shorthand Properties and CSS Custom Properties can simplify Web Component theming APIs.

Read Article