A PostCSS plugin that introduces a new CSS unit: pxv — a pixel that scales with the viewport.
Sometimes layouts need the precision of pixels but the flexibility of viewport units. That’s where pxv comes in: it’s like a pixel that flexes with the viewport.
Input:
.box {
width: 300pxv;
margin-bottom: 16pxv;
}Output:
.box {
width: calc(300 * var(--pxvUnit));
margin-bottom: calc(16 * var(--pxvUnit));
}Which looks like this when computed (note actual code is much trimmer):
:root {
--siteBasis: 375;
--siteMax: 600;
--pxvUnit: clamp(0px, calc((100 / 375) * 1vw), calc(1px * 600 / 375));
}
.box {
width: clamp(0px, calc(300vw * (100 / 375)), calc(300px * 600 / 375));
margin-bottom: clamp(0px, calc(16vw * (100 / 375)), calc(16px * 600 / 375));
}Using pxv means:
- Layout values stay proportional as screens get bigger or smaller
- One shared formula in
:rootreplaces hundreds of repeatedclamp()calls - Adjusting scaling is as simple as tweaking two variables
** Note:** v2.x has configuration changes
Add postcss-pxv to your PostCSS pipeline, then configure it in your postcss.config.js file.
// postcss.config.js
module.exports = {
plugins: [
require('postcss-pxv')({
// 🔧 Main settings
siteMin: 0, // Minimum viewport width in px
siteBasis: 375, // Reference design width
siteMax: 767, // Maximum viewport width in px
writeVars: false, // Automatically injects CSS variables into :root
// 🎛 Optional variable overrides (use if your CSS tokens differ)
vars: {
min: '--siteMin', // default: --site-min
basis: '--siteBasis', // default: --site-basis
max: '--siteMax', // default: --site-max
unit: '--pxvUnit' // default: --pxv-unit
}
})
]
}Then add this line to your code:
--pxvUnit: clamp(0px, calc((100 / 375) * 1vw), calc(1px * 600 / 375));Version 2 outputs cleaner, smaller CSS by centralizing the clamp() logic into a shared --pxvUnit variable.
The plugin automatically injects the needed variables (--siteBasis, --siteMax, --pxvUnit) if they’re not already defined, so it should just work out of the box.
Previously, every use of pxv generated a full clamp() expression inline, leading to significant repetition and larger CSS files. The improved approach now references a shared --pxvUnit variable, drastically reducing repetition and file size—often by up to ~75% for projects with many pxv values.
/* v1 output */
h1 {
font-size: clamp(0px, calc(24vw * (100 / 375)), calc(24px * 600 / 375));
}In v2, the same value references a central variable:
/* v2 output */
:root {
--siteBasis: 375;
--siteMax: 600;
--pxvUnit: clamp(
0px,
calc((100 / var(--siteBasis)) * 1vw),
calc(1px * var(--siteMax) / var(--siteBasis))
);
}
h1 {
font-size: calc(24 * var(--pxvUnit));
}npm install -D postcss-pxv
# or
pnpm add -D postcss-pxv- Install dependencies:
npm installorpnpm install - Edit
index.js - Test locally with
node process-css.jsor link into a project - Open a PR 🚀