Skip to content

Commit

Permalink
add option to avoid converting 1px, close cuth#18
Browse files Browse the repository at this point in the history
  • Loading branch information
cuth committed Dec 22, 2015
1 parent b602ded commit 11f04b0
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 42 deletions.
2 changes: 1 addition & 1 deletion .jshintrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"browser": true,
"node": true,
"bitwise": true,
"camelcase": true,
"camelcase": false,
"curly": false,
"eqeqeq": true,
"esnext": true,
Expand Down
24 changes: 14 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,25 @@ Type: `Object | Null`
Default:
```js
{
root_value: 16,
unit_precision: 5,
prop_white_list: ['font', 'font-size', 'line-height', 'letter-spacing'],
selector_black_list: [],
rootValue: 16,
unitPrecision: 5,
propWhiteList: ['font', 'font-size', 'line-height', 'letter-spacing'],
selectorBlackList: [],
replace: true,
media_query: false
mediaQuery: false,
minPixelValue: 0
}
```

- `root_value` (Number) The root element font size.
- `unit_precision` (Number) The decimal numbers to allow the REM units to grow to.
- `prop_white_list` (Array) The properties that can change from px to rem. Set this to an empty array to disable the white list and enable all properties.
- `selector_black_list` (Array) The selectors to ignore and leave as px.
- `rootValue` (Number) The root element font size.
- `unitPrecision` (Number) The decimal numbers to allow the REM units to grow to.
- `propWhiteList` (Array) The properties that can change from px to rem.
- Set this to an empty array to disable the white list and enable all properties.
- Values need to be exact matches.
- `selectorBlackList` (Array) The selectors to ignore and leave as px.
- `replace` (Boolean) replaces rules containing rems instead of adding fallbacks.
- `media_query` (Boolean) Allow px to be converted in media queries.
- `mediaQuery` (Boolean) Allow px to be converted in media queries.
- `minPixelValue` (Number) Set the minimum pixel value to replace.


### Use with gulp-postcss and autoprefixer
Expand Down
35 changes: 18 additions & 17 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ var defaults = {
selectorBlackList: [],
propWhiteList: ['font', 'font-size', 'line-height', 'letter-spacing'],
replace: true,
mediaQuery: false
mediaQuery: false,
minPixelValue: 0
};

var legacyOptions = {
Expand All @@ -26,29 +27,27 @@ module.exports = postcss.plugin('postcss-pxtorem', function (options) {
convertLegacyOptions(options);

var opts = objectAssign({}, defaults, options);
var pxReplace = createPxReplace(opts.rootValue, opts.unitPrecision);
var pxReplace = createPxReplace(opts.rootValue, opts.unitPrecision, opts.minPixelValue);

return function (css) {

css.walkDecls(function (decl, i) {
// This should be the fastest test and will remove most declarations
if (decl.value.indexOf('px') === -1) return;

if (opts.propWhiteList.length && opts.propWhiteList.indexOf(decl.prop) === -1) return;

if (blacklistedSelector(opts.selectorBlackList, decl.parent.selector)) return;

var rule = decl.parent;
var value = decl.value;

if (value.indexOf('px') !== -1) {
value = value.replace(pxRegex, pxReplace);
var value = decl.value.replace(pxRegex, pxReplace);

// if rem unit already exists, do not add or replace
if (remExists(rule, decl.prop, value)) return;
// if rem unit already exists, do not add or replace
if (declarationExists(decl.parent, decl.prop, value)) return;

if (opts.replace) {
decl.value = value;
} else {
rule.insertAfter(i, decl.clone({ value: value }));
}
if (opts.replace) {
decl.value = value;
} else {
decl.parent.insertAfter(i, decl.clone({ value: value }));
}
});

Expand All @@ -72,10 +71,12 @@ function convertLegacyOptions(options) {
});
}

function createPxReplace (rootValue, unitPrecision) {
function createPxReplace (rootValue, unitPrecision, minPixelValue) {
return function (m, $1) {
if (!$1) return m;
return toFixed((parseFloat($1) / rootValue), unitPrecision) + 'rem';
var pixels = parseFloat($1);
if (pixels < minPixelValue) return m;
return toFixed((pixels / rootValue), unitPrecision) + 'rem';
};
}

Expand All @@ -85,7 +86,7 @@ function toFixed(number, precision) {
return Math.round(wholeNumber / 10) * 10 / multiplier;
}

function remExists(decls, prop, value) {
function declarationExists(decls, prop, value) {
return decls.some(function (decl) {
return (decl.prop === prop && decl.value === value);
});
Expand Down
96 changes: 82 additions & 14 deletions spec/pxtorem-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
'use strict';
var postcss = require('postcss');
var pxtorem = require('..');
var css = '.rule { font-size: 15px }';
var basicCSS = '.rule { font-size: 15px }';

describe('pxtorem', function () {

Expand All @@ -21,38 +21,71 @@ describe('pxtorem', function () {
});

it('should replace the px unit with rem', function () {
var processed = postcss(pxtorem()).process(css).css;
var processed = postcss(pxtorem()).process(basicCSS).css;
var expected = '.rule { font-size: 0.9375rem }';

expect(processed).toBe(expected);
});

it('should replace using a root value of 10', function () {
// Deprecate
it('should replace using a root value of 10 - legacy', function () {
var expected = '.rule { font-size: 1.5rem }';
var options = {
root_value: 10
};
var processed = postcss(pxtorem(options)).process(css).css;
var processed = postcss(pxtorem(options)).process(basicCSS).css;

expect(processed).toBe(expected);
});

it('should replace using a decimal of 2 places', function () {
it('should replace using a root value of 10', function () {
var expected = '.rule { font-size: 1.5rem }';
var options = {
rootValue: 10
};
var processed = postcss(pxtorem(options)).process(basicCSS).css;

expect(processed).toBe(expected);
});

// Deprecate
it('should replace using a decimal of 2 places - legacy', function () {
var expected = '.rule { font-size: 0.94rem }';
var options = {
unit_precision: 2
};
var processed = postcss(pxtorem(options)).process(css).css;
var processed = postcss(pxtorem(options)).process(basicCSS).css;

expect(processed).toBe(expected);
});

it('should only replace properties in the white list', function () {
it('should replace using a decimal of 2 places', function () {
var expected = '.rule { font-size: 0.94rem }';
var options = {
unitPrecision: 2
};
var processed = postcss(pxtorem(options)).process(basicCSS).css;

expect(processed).toBe(expected);
});

// Deprecate
it('should only replace properties in the white list - legacy', function () {
var expected = '.rule { font-size: 15px }';
var options = {
prop_white_list: ['font']
};
var processed = postcss(pxtorem(options)).process(css).css;
var processed = postcss(pxtorem(options)).process(basicCSS).css;

expect(processed).toBe(expected);
});

it('should only replace properties in the white list', function () {
var expected = '.rule { font-size: 15px }';
var options = {
propWhiteList: ['font']
};
var processed = postcss(pxtorem(options)).process(basicCSS).css;

expect(processed).toBe(expected);
});
Expand All @@ -61,14 +94,15 @@ describe('pxtorem', function () {
var rules = '.rule { margin: 16px; font-size: 15px }';
var expected = '.rule { margin: 1rem; font-size: 0.9375rem }';
var options = {
prop_white_list: []
propWhiteList: []
};
var processed = postcss(pxtorem(options)).process(rules).css;

expect(processed).toBe(expected);
});

it('should ignore selectors in the selector black list', function () {
// Deprecate
it('should ignore selectors in the selector black list - legacy', function () {
var rules = '.rule { font-size: 15px } .rule2 { font-size: 15px }';
var expected = '.rule { font-size: 0.9375rem } .rule2 { font-size: 15px }';
var options = {
Expand All @@ -79,16 +113,28 @@ describe('pxtorem', function () {
expect(processed).toBe(expected);
});

it('should ignore selectors in the selector black list', function () {
var rules = '.rule { font-size: 15px } .rule2 { font-size: 15px }';
var expected = '.rule { font-size: 0.9375rem } .rule2 { font-size: 15px }';
var options = {
selectorBlackList: ['.rule2']
};
var processed = postcss(pxtorem(options)).process(rules).css;

expect(processed).toBe(expected);
});

it('should leave fallback pixel unit with root em value', function () {
var options = {
replace: false
};
var processed = postcss(pxtorem(options)).process(css).css;
var processed = postcss(pxtorem(options)).process(basicCSS).css;
var expected = '.rule { font-size: 15px; font-size: 0.9375rem }';

expect(processed).toBe(expected);
});

// Deprecate
it('should replace px in media queries', function () {
var options = {
media_query: true
Expand All @@ -99,6 +145,16 @@ describe('pxtorem', function () {
expect(processed).toBe(expected);
});

it('should replace px in media queries', function () {
var options = {
mediaQuery: true
};
var processed = postcss(pxtorem(options)).process('@media (min-width: 500px) { .rule { font-size: 16px } }').css;
var expected = '@media (min-width: 31.25rem) { .rule { font-size: 1rem } }';

expect(processed).toBe(expected);
});

it('should ignore non px properties', function () {
var expected = '.rule { font-size: 2em }';
var processed = postcss(pxtorem()).process(expected).css;
Expand All @@ -110,7 +166,7 @@ describe('pxtorem', function () {
var rules = '.rule { margin: 0.5rem .5px -0.2px -.2em }';
var expected = '.rule { margin: 0.5rem 0.03125rem -0.0125rem -.2em }';
var options = {
prop_white_list: ['margin']
propWhiteList: ['margin']
};
var processed = postcss(pxtorem(options)).process(rules).css;

Expand All @@ -126,7 +182,7 @@ describe('pxtorem', function () {

it('should not replace values in double quotes or single quotes', function () {
var options = {
prop_white_list: []
propWhiteList: []
};
var rules = '.rule { content: \'16px\'; font-family: "16px"; font-size: 16px; }';
var expected = '.rule { content: \'16px\'; font-family: "16px"; font-size: 1rem; }';
Expand All @@ -137,12 +193,24 @@ describe('pxtorem', function () {

it('should not replace values in `url()`', function () {
var options = {
prop_white_list: []
propWhiteList: []
};
var rules = '.rule { background: url(16px.jpg); font-size: 16px; }';
var expected = '.rule { background: url(16px.jpg); font-size: 1rem; }';
var processed = postcss(pxtorem(options)).process(rules).css;

expect(processed).toBe(expected);
});

it('should not replace values below minPixelValue', function () {
var options = {
propWhiteList: [],
minPixelValue: 2
};
var rules = '.rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }';
var expected = '.rule { border: 1px solid #000; font-size: 1rem; margin: 1px 0.625rem; }';
var processed = postcss(pxtorem(options)).process(rules).css;

expect(processed).toBe(expected);
});
});

0 comments on commit 11f04b0

Please sign in to comment.