A PostCSS plugin that processes CSS unit values through a user-defined function. Use it to convert units (e.g. px to rem, px to vw), scale values, or apply any custom transformation to CSS numeric values.
Features
- Process any CSS unit (
px,rem,vw,em,%, etc.) with a custom function - Filter by property name with wildcard and negation patterns
- Filter by unit type
- Skip specific selectors via blacklist
- Support for media query processing
- Support for custom/non-standard units (e.g.
rpx,dp) - Exclude files by path string, regex, or function
- Optionally append fallback values instead of replacing
Install
npm install postcss postcss-unit-processor --save-dev
Usage
const postcss = require('postcss'); const unitProcessor = require('postcss-unit-processor'); postcss([ unitProcessor({ processor: (value, unit) => { if (unit === 'px') { return value / 16; // returns a number, unit stays px } } }) ]).process(css).css;
The processor function receives the numeric value and unit name, and returns the new value. If nothing is returned (or undefined), the original value is kept unchanged.
processor Function
The core of the plugin. It is called for every matched unit value.
processor(value, unit, node, root)
| Parameter | Type | Description |
|---|---|---|
value |
Number |
The numeric value |
unit |
String |
The unit name (e.g. 'px') |
node |
Object |
The current PostCSS node |
root |
Object |
The PostCSS root node |
Return value:
- Return a
Number— replaces the value, keeps the original unit - Return an
Object{ value, unit }— replaces both value and unit; ifvaluecannot be parsed as a number (e.g.undefined,NaN), it is treated as0 - Return
undefined/ nothing — keeps the original value unchanged
// Return a number: value changes, unit stays the same processor: (value, unit) => value / 16 // 32px → 2px (unit stays px, only the number changes) // Return an object: both value and unit change processor: (value, unit) => ({ value: value / 16, unit: 'rem' }) // 32px → 2rem (both value and unit change) // Return nothing: no change processor: (value, unit) => { if (unit === 'px') return value / 16; // other units: implicitly returns undefined, no change }
Examples
px to rem
unitProcessor({ processor: (value, unit) => { if (unit === 'px') { return { value: value / 16, unit: 'rem' }; } } })
Input/Output:
/* input */ h1 { font-size: 32px; margin: 0 0 16px; border: 1px solid #ccc; } /* output */ h1 { font-size: 2rem; margin: 0 0 1rem; border: 0.0625rem solid #ccc; }
px to vw (responsive design)
unitProcessor({ processor: (value, unit) => { if (unit === 'px') { return { value: (value / 375) * 100, unit: 'vw' }; } } })
Scale all px values by half
unitProcessor({ processor: (value, unit) => { if (unit === 'px') { return value / 2; } } })
Input/Output:
/* input */ h1 { margin: 0 0 20px; font-size: 32px; line-height: 1.2; letter-spacing: 1px; } /* output */ h1 { margin: 0 0 10px; font-size: 16px; line-height: 1.2; letter-spacing: 0.5px; }
Append fallback instead of replacing
unitProcessor({ replace: false, processor: (value, unit) => { if (unit === 'px') { return { value: value / 16, unit: 'rem' }; } } })
/* input */ .box { font-size: 16px; } /* output */ .box { font-size: 16px; font-size: 1rem; }
Options
{ processor: (value) => value, // default: identity function unitPrecision: 5, propList: ['*'], unitList: ['*'], selectorBlackList: [], replace: true, mediaQuery: false, exclude: /node_modules/i, customUnitList: [] }
processor
Type: Function
The unit processing function. See processor Function above.
unitPrecision
Type: Number
Default: 5
Decimal places to round the processed value to.
unitList
Type: Array
Default: ['*']
Which units to pass to the processor function.
// All units (default) unitList: ['*'] // Only px unitList: ['px'] // px and rem unitList: ['px', 'rem'] // All units except rem unitList: ['*', '!rem']
propList
Type: Array
Default: ['*']
Which CSS properties to process.
// All properties (default) propList: ['*'] // Only font-size propList: ['font-size'] // All properties except letter-spacing propList: ['*', '!letter-spacing'] // Properties containing "size" propList: ['*size*'] // Properties starting with "font" propList: ['font*'] // Properties ending with "width" propList: ['*width']
selectorBlackList
Type: Array
Default: []
Selectors to skip. Accepts strings (substring match) or regular expressions.
selectorBlackList: ['.ignore', /^\.no-convert/]
/* .ignore matches the blacklist, skipped */ .ignore { font-size: 16px; } /* → 16px (unchanged) */ /* normal selector, processed */ .convert { font-size: 16px; } /* → processed by your processor function */
replace
Type: Boolean
Default: true
true— replace the original valuefalse— insert the processed value as a new declaration after the original (useful for fallbacks)
mediaQuery
Type: Boolean
Default: false
Whether to process values inside @media queries.
// Enable media query processing mediaQuery: true
/* input */ @media (max-width: 768px) { ... } /* output (with px→rem processor) */ @media (max-width: 48rem) { ... }
exclude
Type: String | RegExp | Function
Default: /node_modules/i
File paths to exclude from processing.
// String: skip files whose path contains this string exclude: 'src/legacy' // RegExp exclude: /\/legacy\//i // Function exclude: (filePath) => filePath.includes('legacy')
customUnitList
Type: Array
Default: []
Additional non-standard units to recognize and process (e.g. rpx used in WeChat Mini Programs, dp used in Android).
customUnitList: ['rpx', 'dp']
Only strings consisting entirely of letters (a-z, A-Z) or the % character are accepted. Invalid entries are silently ignored.
Default recognized units: px, pt, pc, cm, mm, in, %, em, rem, ch, vh, vw, vmin, vmax, ex
Framework Integration
Vite / Vue / React
// vite.config.js import unitProcessor from 'postcss-unit-processor'; export default { css: { postcss: { plugins: [ unitProcessor({ processor: (value, unit) => { if (unit === 'px') { return { value: value / 16, unit: 'rem' }; } } }) ] } } };
webpack (postcss-loader)
// postcss.config.js module.exports = { plugins: [ require('postcss-unit-processor')({ processor: (value, unit) => { if (unit === 'px') { return { value: value / 16, unit: 'rem' }; } } }) ] };
gulp
const gulp = require('gulp'); const postcss = require('gulp-postcss'); const unitProcessor = require('postcss-unit-processor'); gulp.task('css', () => { return gulp.src('src/**/*.css') .pipe(postcss([ unitProcessor({ processor: (value, unit) => { if (unit === 'px') { return value / 2; } } }) ])) .pipe(gulp.dest('dist')); });
License
MIT