Generating custom colour schemes with ENV variables


I had an interesting issue at work this week where we needed to allow for 30 different deployments of the same app to all have a different colour scheme.

Here are some examples of what I mean:

A+ example

SUS example

UEL example

Here’s the flow I ended up using to make this work:

  • Store the colours in the .env file for each deployment
  • Pass the colours to our CSS file using PostCSS and the postcss-env-function plugin
  • Create CSS variables with the colours
  • Pass the CSS variables to Tailwind and generate colour classes from them

The main challenge here is we need to store the colours in a place where it can be changed per app. The most straightforward place to do that is the .env file. However, you can’t (yet) just read the variables from there directly in your CSS files. Fortunately we can read the variables with dotenv and store them in a JS file:

css-env-variables.js

require('dotenv').config()

module.exports = {
  environmentVariables: {
    '--primary-light': process.env.APP_COLOUR_PRIMARY_LIGHT ?? '#E9F7FE',
    '--primary-regular': process.env.APP_COLOUR_PRIMARY_REGULAR ?? '#29ABE2',
    '--primary-dark': process.env.APP_COLOUR_PRIMARY_DARK ?? '#0071BC',
  },
}

We can then use the PostCSS Environment Variables package to make the variables avaiable to use with the CSS env() function:

gulpfile.js

gulp.task('css', function () {
  return gulp
    .pipe(
      postcss([
        postcssEnvFunction({
          importFrom: './css-env-variables.js',
        }),
      ]),
    )
    .pipe(gulp.dest('./public/css/'))
})

Now at this point you could probably use those colours in your tailwind config file directly to generate new classes, but we wanted to make them available as CSS variables first to use in other places, so we did the following:

app.css

:root {
  --primary-light: env(--primary-light);
  --primary-regular: env(--primary-regular);
  --primary-dark: env(--primary-dark);
}

We can now use these colours anywhere in our CSS with var(--primary-light), "var(--primary-regular)" and "var(--primary-dark)".

The final step is passing the colours to Tailwind so it can generate a bunch of colour classes with them:

tailwind.config.js

module.exports = {
  theme: {
    colors: {
      primary: {
        light: 'var(--primary-light)',
        regular: 'var(--primary-regular)',
        dark: 'var(--primary-dark)',
      },
    },
  },
}

And that’s all there is to it. If you want to use your specified regular colour somewhere, you’d append it to the classname, so bg-primary-regular for a background which has the regular colour, for example.

This might all be a lot of extra unnecessary overhead if your app is deploying to one place and only needs one configuration - you could skip all of the ENV stuff by just setting your CSS variables to the colour you want to use:

:root {
  --primary-light: #e9f7fe;
  --primary-regular: #29abe2;
  --primary-dark: #0071bc;
}

I thought it was worth worth sharing how we managed this for multiple apps in case someone else had a similar use case