DEV Community

Desolo Sub Humus 🌎🌍
Desolo Sub Humus 🌎🌍

Posted on • Updated on

Using CSS filters and either CSS variables or @keyframes together

Using CSS filters and either CSS variables or @keyframes together for some different styling tricks

This all started as a personal recipe book. I wanted to create an HTML file for each recipe and another for a menu for navigating the whole thing like a table of contents in a traditional print cookbook. It could be a little messy, since it was to be local files only, but still, if I wanted to create separate styling for different types of recipes, I could end up with an unmanageable cluster of stylesheets rather quickly.

Of course, once I solved that problem with filters, I decided to experiment with my newly created fix to see what else I could do with it. As it turns out, I could make drastic changes fairly easily. I let CSS filters change the colors of each element relative to the background color, experimented with CSS variables (and a bit of JavaScript) to assign different background colors to different pages using little more than a single hex color (rgb, hsl, and named colors work fine, too), and even played around with animating the entire color scheme by adding in a bit of @keyframes API. That said, this still takes more processing in the browser than I'd normally recommend, since I'm a stickler for loading speed, so use these tricks sparingly.

The filters

An easy way to let the browser calculate an entire color palette for a website is to use filters. It's not quite as good as designing using popular prefab color palettes or coming up with a new color palette based on either trends or your own colorful innovation, but it is mathematically valid. For example, let's say you want to create a color palette using a monochromatic color scheme. You could eyeball a color wheel and pick out multiple shades, tints, and tones of the same color, you could use a site like ColorHexa, or you could just let the browser figure it out using filters.


body{background:#9eb89e;}
    /*the body background color is a gray-green tone, almost sage*/

div{border:3px solid #dfe7df;}
    /*the div border is a pale mint*/

p{border:3px solid #353d35;}
    /*the paragraph border is a dark forest green*/

Enter fullscreen mode Exit fullscreen mode

becomes


body{background:#9eb89e;}
    /*the body background color is a gray-green tone, almost sage*/

div{filter:invert(100%);border:3px solid currentColor;}
    /*the div border is a pale mint*/

p{filter:brightness(10%);border:3px solid currentColor;}
    /*the paragraph border is a dark forest green*/

Enter fullscreen mode Exit fullscreen mode

Once all but the main color in your stylesheet is defined by filters calculating new colors based on your main color, changing the entire color scheme is simple, assuming you stick to the same type of color scheme. This will not work well if you plan on going from a monochromatic to a triadic color scheme, but it's perfect for going from one monochromatic scheme to another monochromatic scheme. At this point, you could add in a style switcher that allows the user to control the entire color scheme using a single variable.

The variable

To set this up as a style switcher, you'll need a bit of JavaScript. In this option, you'll be setting up buttons to click on for each color scheme, but altering it to accept input from a form would work just as well. This is only one example.


const root = document.documentElement 
const themeBtns = document.querySelectorAll('.theme > button')

themeBtns.forEach((btn) => {
  btn.addEventListener('click', handleThemeUpdate)
})
    /*this creates the ability to control styles with buttons using the click events*/

function handleThemeUpdate(e) {
  switch(e.target.value) {
    case 'sage': 
      root.style.setProperty('--main', '#9eb89e')
      break
    case 'wetsand': 
      root.style.setProperty('--main', '#b8b89e')
      break
  }
}
    /*this is where we add the styling that changes by way of CSS variables*/

Enter fullscreen mode Exit fullscreen mode

Then all you have to do is reference the script in your HTML, add the class 'theme' to the containing element for your style switcher buttons, add the value and id 'sage' and 'wetsand' to your buttons, and you are ready to use your variable.


body{background:var(--main);}
    /*the body background color is a gray-green tone, almost sage*/

div{filter:invert(100%);border:3px solid currentColor;}
    /*the div border is a pale mint*/

p{filter:brightness(10%);border:3px solid currentColor;}
    /*the paragraph border is a dark forest green*/

Enter fullscreen mode Exit fullscreen mode

Now, at the click of a button, your users can change from one color scheme to another using JavaScript to change one single color, which, in turn, cascades using filters to control all the other colors mathematically. We could make different change and animate the whole process, though.

Animation with the @keyframes API

For an automatically changing color scheme, skip the CSS variable and scripting above and add an @keyframes animation to control the main color.


body{background:#9eb89e;}
    /*the body background color is a gray-green tone, almost sage, as a fallback*/
    /*@keyframes will animate this color scheme in browsers that support it*/

div{filter:invert(100%);border:13px solid currentColor;}
    /*the div border is a paler tint of the body background color*/

p{filter:brightness(10%);border:13px solid currentColor;}
    /*the paragraph border is a darker shade of the body background color */

@keyframes colorSwitch{
0%{background:#9eb89e;}
25%{background:#b8b89e;}
50%{background:#b89eb8;}
75%{background:#9e9eb8;}
100%{background:#9eb89e;}}
body{animation-name:colorSwitch;animation-duration:15s;animation-iteration-count:infinite;}
    /*the main body color will change over the course of 15 seconds and then repeat */

Enter fullscreen mode Exit fullscreen mode

Now the whole style will infinitely loop through four different monochromatic color schemes. To keep the separate schemes from being to jarring when going from one to the next, I chose to use a tetradic color scheme to define all four main colors.

Update: I've created a Gist to demonstrate the use of filters in calculating an entire color scheme using only one specified color in the CSS. Please excuse the garish colors in the examples; they are used to demonstrate how the filters work, NOT as a suggested set of color schemes.

Latest comments (0)