1

how can I use an environment variable to specify the base color in my CSS ?

I use NEXTJS

My colors are all defined as variables in my globals.css :

@layer base {
   :root {
      ...
      --primary: #0096d0;
      --primary-bright: hsl(from var(--primary) h s calc(l*1.5));
      ...

I tried

--primary: env(NEXT_PUBLIC_PRIMARY_COLOR, #0096d0);

But the env variable is ignored

Any idea ?

1 Answer 1

2

While env() does work with custom properties, it reads from UA-defined environment variables, not from the published NEXT_PUBLIC_ variables in the client-side, and definetly not server-side environment variables. Though in the future we might be able to add custom environment variables via JS or CSS, currently you can't define client-side Custom CSS Environment Variables yet.

Hence, for now you will need to either consider using CSS preprocessors, inline-styles in JSX, or PostCSS plugins. They all have their own drawbacks.

Inline Styles

The main disadvantage is that this can't be used in the global.css like you were. However, the advantage is that you can create the style object however you want. You can also update the style object and trigger an update after the app is running. (Note that all NEXT_PUBLIC_ variables will be frozen from being updated during runtime.)

In index.js:

//this can be created dynamically by looping over keys in .env.local
const style = {"--primary": process.env.NEXT_PUBLIC_PRIMARY_COLOR ?? '#0096d0'}
<div style={style}>
    <MyRoot></MyRoot>
</div>

CSS Preprocessors

One way is to import specific environment variables into SCSS variables using the SASS additional-data loader option.

For Next, you can follow the Next document Styling with SCSS to install SASS:

npm install --save-dev sass

In next.config.js, prepend the SASS variables:

const nextConfig = {
  sassOptions: {
    additionalData: Object.keys(process.env).reduce((accumulator, currentValue) => {
      if (currentValue.startsWith('NEXT_THEME_')) {
        return `${accumulator}$${currentValue}: ${process.env[currentValue]};`
      }
      else {
        return accumulator
      }
    }, ''),
    includePaths: [path.join(__dirname, 'styles')],
  }
}

In .env.local:

NEXT_THEME_PRIMARY_COLOR=red
NEXT_THEME_SECONDARY_COLOR='#fff'

Then you can use the environment variables in globals.scss by:

@layer base {
  :root {
    --primary: #{$NEXT_THEME_PRIMARY_COLOR};
  }
}

The drawback is that SCSS is "preprocessed", means that the SCSS variables also don't exist for you to update during JS runtime. Also, the environment variable have to always be presented, or else you need to use variable-exists() or !default explicitly, which is somewhat verbose. For example:

:root {
  --primary: #0096d0;
  @if variable-exists(NEXT_THEME_PRIMARY_COLOR) {
    --primary: #{$NEXT_THEME_PRIMARY_COLOR};
  }
}

PostCSS Plugins

Since you are using Nextjs, PostCSS and some plugins are built-in already. However, currently none of the built-in ones matches your need. You need to find a plugin or implement one that solves your problem.

One example is the postcss-functions plugin that allows you define your own env function that reads from environment variables.

In postcss.config.js:

const theme = Object.keys(process.env).reduce((accumulator, currentValue) => {
  if (currentValue.startsWith('NEXT_THEME_')) {
    accumulator[currentValue] = process.env[currentValue];
    return accumulator;
  }
  else {
    return accumulator
  }
}, {})

function getEnv(variable, fallback = null) {
  return theme[variable] ?? fallback;
}

module.exports = {
  "plugins": {
    "postcss-functions": {
      "functions": {
        getEnv
      }
    },
  }
}

Then you can use it in global.css as follow:

@layer base {
  :root {
    --primary: getEnv(NEXT_THEME_PRIMARY_COLOR, #0096d0);
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! You saved my day man. I went for the SAS solution and it worked like a charm :)
Was glad to help! Note that the additionalData applies to all SCSS files included in includePaths, which is usually fine for variables as they don't exist after compiled, but don't append CSS rules like this directly or they will be duplicated everywhere. I've also updated the solution since I got time to test out some PostCSS plugins.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.