How to set up Sage with postcss custom properties?

How do you set up Sage to use both SCSS and PostCSS’ custom properites?

I’ve already added the postcss custom properties using yarn. Now what? I’m not using any frameworks BTW.

My post.config.js file (which is not working):

/* eslint-disable */

const postcssCustomProperties = require('postcss-custom-properties');

const cssnanoConfig = {
  preset: ['default', { discardComments: { removeAll: true } }]
};

module.exports = ({ file, options }) => {
  return {
    parser: options.enabled.optimize ? 'postcss-safe-parser' : undefined,
    plugins: {
      autoprefixer: true,
      postcssCustomProperties: true,
      cssnano: options.enabled.optimize ? cssnanoConfig : false,
      
    },
  };
};

Doy!

Inside postcss.config.js add preserve: false to compile css variables.

'postcss-custom-properties': { preserve: false, },

Hi @djmtype
could you help me to get it to works?

I installed postcss-custom-properties:
yarn add postcss-custom-properties --dev --ignore-engines

Then, my postcss.config.js file. I tried all the below solutions but none of them worked

/* eslint-disable */

const postcssCustomProperties = require('postcss-custom-properties');

const cssnanoConfig = {
  preset: ['default', { discardComments: { removeAll: true } }]
};

module.exports = ({ file, options }) => {
  return {
    parser: options.enabled.optimize ? 'postcss-safe-parser' : undefined,
    plugins: {
      autoprefixer: true,
      // postcssCustomProperties: true,
      // 'postcss-custom-properties': { preserve: false, },
      postcssCustomProperties: {
        preserve: false,
      },
      cssnano: options.enabled.optimize ? cssnanoConfig : false,
    },
  };
};

I get errors like

 ERROR  Failed to compile with 1 errors                                                                                       10:36:17

 error  in ./resources/assets/styles/main.scss

Syntax Error: /Users/xxx/xxx/xxx/wp-content/themes/xxx/node_modules/is-url-superb/index.js:11
        } catch {
                ^

SyntaxError: Unexpected token {


 @ ./resources/assets/styles/main.scss

Thanks

@dangelion Seems like you might have a general css error – a syntax error more specifically.

What happens if you comment out: postcssCustomProperties: { preserve: false, },?

What does your main.scss file look like?

Hi @djmtype
commenting that line I’ve that error posted above.
Only commenting the
const postcssCustomProperties = require('postcss-custom-properties');
the errors gone away. It seems that line causing error :thinking:

My main.scss, but don’t think the problem comes from here

@import "utils/mixins";
@import "common/fonts"; // @font-face have to be first in compiled CSS
@import "common/variables";
// Normalize.css
// @import "~normalize.css/normalize.css";
@import "common/typography";
@import "common/global";
@import "components/buttons";
//@import "components/comments";
@import "components/forms";
// @import "components/wp-classes";
@import "layouts/header";
@import "layouts/sidebar";
@import "layouts/footer";
@import "layouts/pages";
@import "layouts/posts";
@import "common/grid";
@import "common/animations";
@import "common/editor-styles";
@import "components/menu";
@import "components/section";
@import "components/hero";
@import "components/card";
@import "components/modal";
@import "components/carousel";
@import "layouts/tinymce";

I assume you’ve tried the process of elimination? If you comment out all of your scss imports except the first, then run yarn build does it error out?

BTW, here’s my entire postcss.config.js config that’s working with Sage 9:

/* eslint-disable */

const cssnanoConfig = {
  preset: ['default', { discardComments: { removeAll: true } }]
};

module.exports = ({ file, options }) => {
  return {
    parser: options.enabled.optimize ? 'postcss-safe-parser' : undefined,
    plugins: {
      autoprefixer: true,
      cssnano: options.enabled.optimize ? cssnanoConfig : false,
      'postcss-inline-svg' : { removeFill: false },
    },
  };
};

My package.json for versions:

"devDependencies": {
    "autoprefixer": "~8.2.0",
    "browser-sync": "2.26.3",
    "browsersync-webpack-plugin": "^0.6.0",
    "bs-html-injector": "~3.0",
    "buble-loader": "^0.4.1",
    "cache-loader": "~1.2.5",
    "clean-webpack-plugin": "^0.1.18",
    "copy-globs-webpack-plugin": "^0.2.0",
    "css-loader": "^0.28.9",
    "cssnano": "~4.0.5",
    "eslint": "~4.19.1",
    "eslint-loader": "~1.9",
    "eslint-plugin-import": "~2.14.0",
    "extract-text-webpack-plugin": "~3.0.2",
    "file-loader": "^1.1.6",
    "friendly-errors-webpack-plugin": "^1.6.1",
    "imagemin-mozjpeg": "~7.0.0",
    "imagemin-webpack-plugin": "~2.2.0",
    "import-glob": "~1.5",
    "node-sass": "~4.9.4",
    "postcss-loader": "~2.1.0",
    "postcss-safe-parser": "~3.0",
    "resolve-url-loader": "~2.3.1",
    "rimraf": "~2.6",
    "sass-loader": "~6.0",
    "style-loader": "^0.22.1",
    "stylelint": "^8.4.0",
    "stylelint-config-standard": "~18.2.0",
    "stylelint-webpack-plugin": "^0.10.5",
    "uglifyjs-webpack-plugin": "^1.3.0",
    "url-loader": "^0.6.2",
    "webpack": "~3.10.0",
    "webpack-assets-manifest": "^1.0.0",
    "webpack-dev-middleware": "~2.0.4",
    "webpack-hot-middleware": "~2.22.3",
    "webpack-merge": "~4.1.4",
    "yargs": "~11.0.0"
  },
  "dependencies": {
    "jquery": "^3.3.1",
    "postcss-custom-properties": "^9.1.1",
    "postcss-inline-svg": "^4.1.0",
  }

I tried to commenting all @imports except the first @import "utils/mixins"; and also commenting all the main.scss but I’ve the same error.

I checked your postcss.config.js but it’s the Sage default with the add of ‘postcss-inline-svg’. No trace of postcss-custom-properties… I’m confused, where you set it?

My package.json

  "devDependencies": {
    "autoprefixer": "~8.2.0",
    "browser-sync": "~2.24.7",
    "browsersync-webpack-plugin": "^0.6.0",
    "bs-html-injector": "~3.0",
    "buble-loader": "^0.4.1",
    "cache-loader": "~1.2.5",
    "clean-webpack-plugin": "^0.1.18",
    "copy-globs-webpack-plugin": "^0.2.0",
    "css-loader": "^0.28.9",
    "cssnano": "~4.0.5",
    "eslint": "~4.19.1",
    "eslint-loader": "~1.9",
    "eslint-plugin-import": "~2.14.0",
    "extract-text-webpack-plugin": "~3.0.2",
    "file-loader": "^1.1.6",
    "friendly-errors-webpack-plugin": "^1.6.1",
    "imagemin-mozjpeg": "~7.0.0",
    "imagemin-webpack-plugin": "~2.2.0",
    "import-glob": "~1.5",
    "node-sass": "~4.9.4",
    "postcss-custom-properties": "^10.0.0",
    "postcss-loader": "~2.1.0",
    "postcss-safe-parser": "~3.0",
    "resolve-url-loader": "^3.1.1",
    "rimraf": "~2.6",
    "sass-loader": "~6.0",
    "style-loader": "^0.22.1",
    "stylelint": "^8.4.0",
    "stylelint-config-standard": "~18.2.0",
    "stylelint-webpack-plugin": "^0.10.5",
    "uglifyjs-webpack-plugin": "^1.3.0",
    "url-loader": "^0.6.2",
    "webpack": "~3.10.0",
    "webpack-assets-manifest": "^1.0.0",
    "webpack-dev-middleware": "~2.0.4",
    "webpack-hot-middleware": "~2.22.3",
    "webpack-merge": "~4.1.4",
    "yargs": "~11.0.0"
  },
  "dependencies": {
    "bootstrap": "^4.5.2",
    "custom-event-polyfill": "^1.0.7",
    "jquery": "^3.3.1",
    "normalize.css": "^8.0.1",
    "popper.js": "^1.16.1",
    "rfs": "^9.0.3",
    "swiper": "^6.3.2"
  }

I’m utilizing css custom properties and therefore don’t want postcss to pre-process them which is why I haven’t defined it.

With that said, when setting, 'postcss-custom-properties': { preserve: false, } on yarn start, this will work, but naturally break any styles where variables (css custom properties) have been re-defined.

However, running with'postcss-custom-properties': { preserve: false, } on yarn build:production will absolutely fail and should fail if you have variables being re-defined.

You’ll end up getting a similar error:

error  in ./resources/assets/styles/main.scss

Module build failed: ModuleBuildError: Module build failed: Syntax Error 

(1:1) Unknown word

> 1 | var(--s0)*var(--ratio)
    | ^

Check you scss files for something like the following:

// Example: 

:root {
--size: 20rem;
)

.some-selector {
--size: 12rem;
max-width: var(--size);
}

@dangelion You’re also using a different version for postcss-custom-properties among other modules, which is why I posted my package.json. They are not the same.

https://www.diffchecker.com/9vDIuffh

So if you’re still getting errors, try rolling back postcss-custom-properties to version 9.1.1 and see if that works.

Yes, that was the version! From postcss-custom-properties v10 is required node 10 that I have not. Installed the v9.2.0 and worked!

Interesting what you’re saying before. Then if I understand you’re not actually using postcss-custom-properties but native custom properties. They’re not supported by IE, how you handle that?

I was thinking to use postcss-custom-properties with { preserve: true } so it will keep custom properties but add a standard css fallback readable from IE. Am I right?

However trying so, I see the compiled fallbacks with nested calc() are invalid again on IE…

Anyway, I realized that this technique doesn’t handle a redraw via media query (ie. reassigning a variable).
I mean:

:root {
  --color: red;
}

@media screen and (min-width: 992px) {
  :root {
    --color: blue;
  }
}

body { background: var(--color) }

And for many reason I can’t re-write the rule body inside the media query.
What’s your advice on this?

I’m mainly using postcss in my project so I can easily assign fill colors to my background SVG icons.

Progressive enhancement and accessibility are very valid points. If your site needs IE11 and older support, using custom properties or feature queries (@supports) won’t work. In our specific use case, fortunately, my project didn’t require it.

In the past I’ve also used a Sass mixin library (https://github.com/malyw/css-vars) to address custom properties when/if my project was ready to drop support on older browsers. So, this library did not automatically produce fallbacks to variables.

But, it was possible to reassign your variables so long as you weren’t reassigning variables to other variables.

Instead of declaring your variables in the :root, you’d define them inside an @include css-vars statement. But, I haven’ tested this lately with Sage.

I thought I’d add a helpful Chromium plugin for checking appearance and behavior when modern features are not supported.

1 Like

@dangelion ALSO, if you happen to set: 'postcss-custom-properties': { preserve: true, }, it will also error out in production because it doesn’t know how to handle calculating variables with other variables.

For example, for handling vertical rhythm I had used the following approach. This was time-saving when testing because I only needed to concern myself with the ratio value. However, this will not compile when needing fallback values:

	--ratio: 1.25;

	--s0: 1.0rem;
	--s1: calc(var(--s0) * var(--ratio));
	--s2: calc(var(--s1) * var(--ratio));
	--s3: calc(var(--s2) * var(--ratio));
	--s4: calc(var(--s3) * var(--ratio));
	--s5: calc(var(--s4) * var(--ratio));
	--s6: calc(var(--s5) * var(--ratio));
	--s-1: calc(var(--s0) / var(--ratio));
	--s-2: calc(var(--s-1) / var(--ratio));
	--s-3: calc(var(--s-2) / var(--ratio));
	--s-4: calc(var(--s-3) / var(--ratio));
	--s-5: calc(var(--s-4) / var(--ratio));
	--s-6: calc(var(--s-5) / var(--ratio));

Thanks for your answers. Don’t know if css-vars is what I’m searching for…

Very useful this one! css-feature-toggle-devtools-extension

About the { preserve: true }: strange, because I just tried it today (yarn build:production) and it worked perfectly. No errors. I use your same approach for typography and spacings.
The only thing didn’t worked was the reassigning of variables inside media queries, as posted before. I was just thinking to keep this solution with just this compromise.