Skip to content

Instantly share code, notes, and snippets.

@rynbyjn
Created June 14, 2019 16:03
Show Gist options
  • Save rynbyjn/ca05be5e4f95e04acfc1d902fe9782db to your computer and use it in GitHub Desktop.
Save rynbyjn/ca05be5e4f95e04acfc1d902fe9782db to your computer and use it in GitHub Desktop.
A stylis.js plugin to convert pixel values to rem values
// Based on the [postcss-pxtorem plugin](https://github.com/cuth/postcss-pxtorem)
const minPixelValue = 4
export const ROOT_VALUE = 16
const unitPrecision = 5
// See https://github.com/cuth/postcss-pxtorem/blob/master/lib/pixel-unit-regex.js
const pxRegExp = /"[^"]+"|'[^']+'|url\([^)]+\)|(\d*\.?\d+)px/gi
// Not an exhaustive list but should cover most use cases:
// https://developer.mozilla.org/en-US/docs/Web/CSS/Reference
const blacklist = [
'column-count',
'columnCount',
'counter-increment',
'counter-reset',
'counterIncrement',
'counterReset',
'flex',
'flex-grow',
'flex-order',
'flex-shrink',
'flexGrow',
'flexOrder',
'flexShrink',
'font-weight',
'fontWeight',
'opacity',
'order',
'stroke-miterlimit',
'stroke-width',
'strokeMiterlimit',
'strokeWidth',
'z-index',
'zIndex',
]
const isNumberPropBlacklisted = prop =>
blacklist.some(property => property === prop)
const isValueInRange = value => Math.abs(value) > minPixelValue
const toFixed = (num, precision) => {
const multiplier = 10 ** (precision + 1)
const wholeNumber = Math.floor(num * multiplier)
return (Math.round(wholeNumber / 10) * 10) / multiplier
}
const toRem = value => {
const fixed = toFixed(Number(value) / ROOT_VALUE, unitPrecision)
return fixed === 0 ? '0' : `${fixed}rem`
}
const pixelReplace = () => (pxValue, numValue) => {
if (!numValue) {
return pxValue
}
if (!isValueInRange(numValue)) {
return pxValue
}
return toRem(numValue)
}
export default (context, content) => {
if (context !== 1) {
return
}
const newStyleArr = content.split(':')
const pxReplace = pixelReplace()
const prop = newStyleArr[0]
const value = newStyleArr[1]
const numValue = Number(value)
if (
!isNaN(numValue) &&
isValueInRange(numValue) &&
!isNumberPropBlacklisted(prop)
) {
newStyleArr[1] = toRem(numValue)
} else if (typeof value === 'string' && value.includes('px')) {
newStyleArr[1] = value.replace(pxRegExp, pxReplace)
}
return newStyleArr.join(':')
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment