postcss-preset-env: future CSS today
postcss-preset-env is a bundle of several dozen plugins in one package. It lets you write modern CSS and, for browsers in your Browserslist list that lack a feature, rewrites the code into an older equivalent. Autoprefixer is already inside.
Installing
Install the package and use it instead of Autoprefixer in the config:
npm install --save-dev postcss-preset-env
npm uninstall autoprefixer// postcss.config.js
import postcssPresetEnv from 'postcss-preset-env';
export default {
plugins: [postcssPresetEnv()],
};The browser list is still "browserslist": ["defaults"] in package.json.
Logical properties
Logical properties set spacing and borders not by screen sides (left, top) but by text direction: inline runs along a line, block runs across lines. Let us style the post card:
/* styles/main.css */
.post-card {
margin-block: 16px;
padding-inline: 24px;
border-inline-start: 4px solid #2563eb;
}After npx postcss styles/main.css -o css/main.css:
.post-card {
margin-top: 16px;
margin-bottom: 16px;
padding-left: 24px;
padding-right: 24px;
border-left: 4px solid #2563eb;
}The logical properties were replaced with physical ones. The reason is Opera Mini, which is part of defaults and does not understand them. The replacement assumes left-to-right text.
<style>
.post-card {
margin-top: 16px;
margin-bottom: 16px;
padding-left: 24px;
padding-right: 24px;
border-left: 4px solid #2563eb;
}
</style>
<article class="post-card">
<h2>Getting to know PostCSS</h2>
<p>Anna shows how to set up plugins in ten minutes.</p>
</article>The page shows a card with a blue stripe on the left and spacing — just as the original code would look in a modern browser.
Other features
The same plugin handles colors and math functions:
/* styles/main.css */
.post-tag {
color: oklch(55% 0.2 260);
font-size: clamp(0.75rem, 2vw, 0.875rem);
}.post-tag {
color: rgb(28, 105, 227);
font-size: max(0.75rem, min(2vw, 0.875rem));
}The oklch() color was converted to rgb(), and clamp() was expressed with max() and min().
The result depends on the list
Change the list to "browserslist": ["baseline widely available"] and build again: the card keeps margin-block and padding-inline, and the color stays in oklch(). Every browser in the new list understands them, so the plugin has nothing to change. When old browsers no longer matter, you just update the list — the source CSS stays as it is.
Options
| Option | What it does |
|---|---|
stage | How experimental the enabled features may be: from 0 (drafts) to 4 (standard), 2 by default |
features | Turn a single feature on or off by its name |
browsers | Set the browser list right here, bypassing Browserslist |
For example, this turns off the logical properties replacement:
// postcss.config.js
import postcssPresetEnv from 'postcss-preset-env';
export default {
plugins: [
postcssPresetEnv({
features: { 'logical-properties-and-values': false },
}),
],
};All feature names are listed on cssdb.org.
Common mistake
Using logical properties on a site with Arabic or Hebrew text and missing the replacement. The plugin turns border-inline-start into border-left, and in right-to-left text the stripe ends up on the wrong side. For such sites, exclude Opera Mini from the list or turn the feature off with features.