webdevfrontendtutorialsCSSJavaScript

Build a custom palette using color-mix() in TailwindCSS

Apr 19, 2023 ยท 9 min read
Buy Me A Coffee
Build a custom palette using color-mix() in TailwindCSS

In this post, we will see how to use CSS function color-mix() with CSS variables to generate a custom palette for our Nuxt application efficiently with TailwindCSS.

Table of Content

Prerequisites

It would be best if you had your Nuxt application set up by using the following command:

npx nuxi init tailwindcss-color-mix

Selecting TailwindCSS as a dependency during the installation prompts would be best.

Once created, within the project's root directory, you should create two files - one is tailwind.css located in the styles folder with the following code:

/** styles/tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

And we create another file, tailwind.config.js, for extending the configuration of TaiwindCSS in the project:

/** tailwind.config.js */
module.exports = {
}

Then in nuxt.config.js, you need to set the tailwindcss plugin's configuration with the following code:

/** nuxt.config.js */
export default {
    //...
      tailwindcss: {
        cssPath: '~/styles/tailwind.css',
        configPath: '~/tailwind.config.js'
      },
}

And we are ready for our tutorial!

Understanding color palette variants

A TailwindCSS color palette is a set of colors divided into two sections: the lighter colors (tint variants) and the darker colors (shade variants). The tint variants are in the scope of 50 to 400, and the darker colors are from 600 to 900, with the base color as a variant of 500. An example of the TailwindCSS palette for color #96454c is as below:

Color variants for Copper Rust color

There are many ways to generate color palette variants. You can use Color Palette Generator to build a palette from an image or build your mechanism to take a color and generate the appropriate palette using JavaScript.

Or you can use the CSS function - color-mix() to achieve this goal.

Generate the palette with tint and shade variants with color-mix()

color-mix() is a CSS function that accepts two colors and returns the desired mixed color variant based on a given color space. To use color-mix(), we will need to define the colorSpace for calculating the value of mixing the baseColor and the blendingColor, as in the following syntax:

color-mix(
    in colorSpace, 
    baseColor <baseColorPercent>, 
    blendingColor <blendingColorPercent>
)

We can also indicate the baseColorPercent percentage of the baseColor and blendingColorPercent of blendingColor the browser should use for mixing, when applicable. Below is an example of mixing 50% red color with 20% white color in sRGB color space with color-mix():

Mixed color generated in CSS

While the baseColor and blendingColor can be any CSS-supported color values, we can also use color-mix() for different color spaces for color mixing, from sRGB to HSL. The result color will vary per chosen color space. For this post, we will use sRGB as our color space.

Now we understand how color-mix() works, we will explore how we generate the tint and share variants for our Tailwind color palette.

Generating tint variants

As mentioned, the tint variants are lighter shades of a base color, resulting from blending a base color with white at a certain intensity level (or percentage).

In other words, we create a new variant by mixing a color with a percentage of white, using color-mix() with the following formula:

color-mix(in srgb, <color>, white <whitePercentage>)

Based on the above formula, we implement a function getTintVariantColor which accepts a base color and an intensity value from 0 to 1 and returns a string containing the appropriate CSS code with color-mix:

function getTintVariantColor(color, intensity) {
    return `color-mix(in srgb, ${color}, white ${intensity * 100}%)`
}

And since we need the variants of 50, 100, 200, and 400 for our tints, we can gradually increase the values whitePercentage for each variant level accordingly, as in the following example:

const tintVariants = {
    50: 0.95, //95%
    100: 0.9, //90%
    200: 0.7, //70%
    300: 0.5, //50%
    400: 0.3, //30%
}

Great. Now let's head to the tailwind.config.js file and provide our custom palette from the primary color #96454c, using the theme.extend.colors field in the tailwind.config.js file, as follows:

module.exports = {
  theme: {
    extend: {
      colors: {
        primary: {
          50: getTintVariantColor('#96454c', tintVariants.50),
          100: getTintVariantColor('#96454c', tintVariants.100),
          200: getTintVariantColor('#96454c', tintVariants.200),
          300: getTintVariantColor('#96454c', tintVariants.300),
          400: getTintVariantColor('#96454c', tintVariants.400),
          500: '#96454c',
        }
      },
    }
  },
}

That's it. When you add the following code to the pages/index.vue file, you will see the tint color palette for the primary color #96454c:

<template>
  <main class="flex items-center flex-col gap-5 my-10">
    <h1>Current template:</h1>
    <h2 class="text-primary-500">Base color: #96454c</h2>
    <ul style="width: 200px">
      <li 
        v-for="variant in palettes" 
        :class="`bg-primary-${variant} px-3 py-2 ${ variant > 500 ? 'text-white': ''}`"
        key="variant"
      >
        {{variant}}
      </li>
    </ul>
  </main>
</template>
<script setup>
const palettes = [50, 100, 200, 300, 400, 500]
</script>
Tint variants

Since we are dynamically computing the classes in the template, we need to add primary color's class pattern to the safelist of TailwindCSS configuration. Otherwise, TailwindCSS will not generate the relevant classes since it thinks they are unused.

module.exports = {
    //...
    safelist: [
        {
            pattern: /\-primary\-/,
        }
    ]
}

Alternatively, we can also define the percentage of our base color instead of white for our color mixer. In this case, we calculate the colorPercentage value as 100% - whitePercentage for each intensity level:

const tintVariantsForBaseColor = {
    50: 0.05, //95% white
    100: 0.1, //90%
    200: 0.3, //70%
    300: 0.5, //50%
    400: 0.7, //30%
}

And our formula will change to the following:

color-mix(in srgb, <color> <colorPercentage>%, white)

The result should remain the same as the previous implementation.

Next, we will apply the same approach to generate the shade variants.

Generating shade variants

While the tints are the variants that resulted from mixing a color with white, as darker variants, shades are the colors that resulted from mixing our target color with black at some intensity level. Following the previous formula for the tint colors, we can write a function getShadeVariantColor() in a similar way:

function getShadeVariantColor(color, intensity) {
    return `color-mix(in srgb, ${color}, black ${intensity * 100}% )
}

And we also need to define the intensity level, on a scale of 0 to 1, as the variants of 600, 700, 800, and 900 for our shades, by gradually increasing its value by 0.2 (20%):

const tintVariants = {
    600: 0.1, //10%
    700: 0.3, //30%
    800: 0.5, //50%
    900: 0.7, //70%
}

Then in tailwind.config.js, we will use the getShadeVariantColor() function to generate the remaining variants for our primary color:

module.exports = {
  theme: {
    extend: {
      colors: {
        primary: {
            //...
            600: getShadeVariantColor('#96454c', shadeVariants.600),
            700: getShadeVariantColor('#96454c', shadeVariants.700),
            800: getShadeVariantColor('#96454c', shadeVariants.800),
            900: getShadeVariantColor('#96454c', shadeVariants.900),
        }
      },
    }
  },
}

And in the pages/index.vue file, we can add the remaining variant codes to palettes as follows:

<script setup>
const palettes = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900]
</script>

We will now see the whole palette displayed in the browser:

Color variants for #96454c

Great. But what if we want to change the primary base color to another? Manually replacing each row of the variant's calculation can be inefficient. We need to find a way to make it more dynamic, such as using the help or currentColor or CSS variables. Let's explore it next.

Using color-mix() with currentColor and CSS variables

Unfortunately, we can't use currentColor inside color-mix(). However, we can use CSS variables with the help of the var() function and color-mix().

Take our example color palette, for instance. Instead of mapping the color code directly in the configuration file, we can assign a CSS variable --color-primary-base to the extensive base layer in our tailwind.css file, as follows:

/**styles/tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
    :root {
      --color-primary-base: #96454c;
    }
  }

Then in tailwind.config.js, we will change the value of #96454c to var(--color-primary-base):

colors: {
    'primary': {
        50: 'color-mix(in srgb, var(--color-primary-base) 5%, white)',
        100: 'color-mix(in srgb, var(--color-primary-base) 10%, white)',
        200: 'color-mix(in srgb, var(--color-primary-base) 30%, white)',
        300: 'color-mix(in srgb, var(--color-primary-base) 50%, white)',
        400: 'color-mix(in srgb, var(--color-primary-base) 70%, white)',
        500: 'var(--color-primary-base)',
        600: 'color-mix(in srgb, var(--color-primary-base), black 10%)',
        700: 'color-mix(in srgb, var(--color-primary-base), black 30%)',
        800: 'color-mix(in srgb, var(--color-primary-base), black 50%)',
        900: 'color-mix(in srgb, var(--color-primary-base), black 70%)',
    },
},

The result stays the same, but whenever we want to change the primary base color, we only need to change the value of --color-primary-base in the main CSS file.

Browser support

At the point of writing, most browsers support this feature except Firefox version 88 and above. Hence, consider implementing a fallback if Firefox is required.

Resources

Summary

In this tutorial, we have briefly learned how to build a variant palette for color using CSS functions color-mix(), var(), CSS variables, and JavaScript in a TailwindCSS-Nuxt-powered application. Indeed, you can use the same approach to calculate the color themes for any web application development, not limited to Nuxt and TailwindCSS.

While color-mix() can be helpful in pure CSS in many cases, it may not be the optimal choice due to the browser limitation (Firefox). In such scenarios, using the built-in functionality of TailwindCSS for theming or an external tool like Color Palette Generator may be a better solution. Nevertheless, the power of pure CSS is getting more robust with more handy features, which is worth waiting for!

If you have tried CSS functions like color-mix() or any other, share your experience with me in the comment section!

๐Ÿ‘‰ If you'd like to catch up with me sometimes, follow me on Twitter | Facebook.

๐Ÿ‘‰ Learn about Vue with my new book Learning Vue. The early release is available now!

Like this post or find it helpful? Share it ๐Ÿ‘‡๐Ÿผ ๐Ÿ˜‰

Buy Me A Coffee