Cover image for PostCSS Preset Env: Babel for CSS

PostCSS Preset Env: Babel for CSS

adrianbdesigns profile image Adrian Bece ・3 min read

PostCSS has been my personal favorite out of all the tools (or flavors) for writing CSS for the past year and a half. Setup is really easy, it features tons of extremely useful plugins and it has great performance. One of my favorite plugins is definitely postcss-preset-env.

What is postcss-preset-env?

Basically, it’s Babel for CSS. It allows developers to write CSS using modern and future syntax and transpiles that code to CSS which is widely supported by most browsers. Sounds simple, right?

For example, this allows developers to use CSS variables in their regular CSS code. Depending on the config, postcss-preset-env includes regular values alongside CSS variables as fallback for browsers that do not support CSS variables.


.cta:hover {
  background-color: var(--color__cta--darker);
  color: var(--color__secondary);

Alt Text


  1. Install it using npm: npm install postcss-preset-env --save-dev
  2. Add it to your PostCSS plugins config: gulp, webpack, postcss config file, etc. For example, in postcss.config.js we can include it like this:
module.exports = {
  plugins: {
    "postcss-preset-env": { /* Options */ },

With default config, postcss-preset-env uses Stage 2 CSS features (which we’ll explain later) and targets all browsers (if no browsers option is set in the project).

Basic Configuration

I want to cover only the most used and most important config options, and those are stage, features and browsers. You can check the list of all options in the docs.


This is similar to ECMAScript proposals used in Babel. The stages represent the steps that each feature (or proposal) in CSS must go through to become a part of the CSS standard. It consists of the following stages:

  • Stage 0: Aspirational - an idea or an early draft. Highly unstable and subject to change
  • Stage 1: Experimental - also highly unstable and subject to change, but the proposal is recognized by the members of W3C.
  • Stage 2: Allowable - also highly unstable and subject to change, but it’s actively being worked on.
  • Stage 3: Embraced - stable and subject to little change. This feature will likely become a standard.
  • Stage 4: Standardized - final working solution. supported by all major browsers.

By setting a stage option, we are choosing groups of CSS features that we can be used when writing CSS:

    "postcss-preset-env": {
      stage: 3

Useful links for keeping track of which CSS features are in what stage:


We can use the feature config to only enable specific CSS features, regardless of which stage option has been set.

All feature variables can be found here: https://preset-env.cssdb.org/features

In the following example, we use all stage 3+ features and we include nesting-rules feature which is a stage 1 feature.

    "postcss-preset-env": {
      stage: 3,
      features: {
        "nesting-rules": true


This is a standard Browserlist config that is being used by various tools and plugins like Autoprefixer.

In the following example, we are only targeting the last 2 versions of the browser.

    "postcss-preset-env": {
      browsers: "last 2 versions",
      stage: 3,
      features: {
        "nesting-rules": true

Full config and docs

These several options are more than enough to get you started with using postcss-preset-env and write modern CSS syntax that transpiles down to widely-supported CSS syntax. For the full list of config options and features, you can check the following links

Thank you for taking the time to read this post. If you've found this useful, please give it a ❤️ or 🦄, share and comment.

Posted on by:

adrianbdesigns profile

Adrian Bece


React, Frontend, Magento 2 certified developer. Magento PWA Studio contributor. Rock and metal music fan. Reads Dune, sci-fi novels and Calvin & Hobbes. Creates amazing interfaces @ prototyp.digital


markdown guide

Hello Adrian,

I was searching for post css solution regarding css variables and I found exactly what you wrote in article. But unfortunately, my output doesn't seem like yours.
here's the screen of my code:
and result screen seen on ie11 :

if I put css variable on :root, then ie 11 support it as fallback ie. width:300px, width var(--column). or I'll have to write css like width:var(--column, 300px); but that won't be solution what I wanted. all I want to write like width:var(--column) and output should support in ie11 with fallback using postcss.

can you help me on this??


I assume that the issue is that .grid-item doesn't have any relation to .grid once it's compiled to CSS. I think that the CSS would apply either if .grid-item is a child of .grid - .grid .grid-item or if you moved the variable to :root.


Thanks for the reply. I even tried movign css variable to .grid-item but it doesn't see to work. it just with at ie support is not working, beside that other browsers are supporting pretty well. there will be complex cases where we want css variables to be assign in certain viewport only I think this is the best featre of css variables but if we have to write all variable to :root then this won't be good solution either. some variables I want to be scoped to specific component rather than assigning to root of the document. So bottom line, when working with complex media query to css variables, it will trigger problems in IE and that's what my issue is.

Yeah, postcss-preset-env and IE cannot handle the case of dynamic variable values. We just have to wait for IE11 userbase to shrink even more.

Using a CSS in JS systems like styled components fix that issue by using regular JS variables. But that depends on your tech stack.


good article. I personally use a mix of different PostCSS plugins for Sass-like syntax with PreCSS

GitHub logo jonathantneal / precss

Use Sass-like markup in your CSS

PreCSS PostCSS Logo

NPM Version Build Status Support Chat

PreCSS lets you use Sass-like markup and staged CSS features in CSS.

$blue: #056ef0
$column: 200px
.menu {
  width: calc(4 * $column)

.menu_link {
  background: $blue;
  width: $column;

/* becomes */

.menu {
  width: calc(4 * 200px);

.menu_link {
  background: #056ef0;
  width: 200px;

PreCSS combines Sass-like syntactical sugar — like variables, conditionals, and iterators — with emerging CSS features — like logical and custom properties, media query ranges, and image sets.


Add PreCSS to your build tool:

npm install precss --save-dev


Use PreCSS to process your CSS:

import precss from 'precss';



Add PostCSS to your build tool:

npm install postcss --save-dev

Use PreCSS as a plugin:

import postcss from '

Thank you very much. Yeah, I totally understand using Sass variables. I've been using postcss-simple-vars for Sass-like syntax until I've felt comfortable switching to CSS variables.

It's awesome how PostCSS can be flexible and offer different syntaxes, plugins, and flavors.