├── .editorconfig ├── .gitattributes ├── .gitignore ├── .jshintrc ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── lib └── pixrem.js ├── package.json └── test └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "curly": true, 7 | "eqeqeq": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": false, 11 | "newcap": true, 12 | "noarg": true, 13 | "quotmark": "single", 14 | "regexp": true, 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "white": true 21 | } 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - stable 4 | - "10" 5 | - "8" 6 | - "6" 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Release History 2 | 3 | 4.0.1, July 06, 2017 4 | 5 | * Fix CI build, testing only Node.js 4, 6 and stable 6 | 7 | 4.0.0, July 06, 2017 8 | 9 | * Update to PostCSS 6.0 (no longer support Node.js 0.12) 10 | * Update to Browserslist 2.0 11 | 12 | 3.0.2, August 22, 2016 13 | * Fix reduce-css-calc security bug 14 | 15 | 3.0.1, May 24, 2016 16 | * Fix #54: fallback not added when ie9 and ie 10 are in scope 17 | 18 | 3.0.0, Sep 23, 2015 19 | 20 | * Export module as a PostCSS plugin (#35) 21 | * Follow PostCSS plugin guidelines 22 | * Removed `rootValue` parameter, now defined in options (#40) 23 | * Removed old API. Always use pixrem with PostCSS API. 24 | * Added: `unitPrecision` for rounded values 25 | 26 | 2.0.1, Sep 17, 2015 27 | 28 | * Fix NaNpx values (#45) 29 | 30 | 2.0.0, Aug 24, 2015 31 | 32 | * Update to PostCSS 5.0 33 | 34 | 1.3.2, Aug 24, 2015 35 | 36 | * Unpublished version 37 | 38 | 1.3.1, Jul 9, 2015 39 | 40 | * Fixed: Replace `eachDecl` with `each` and `decl.type` check in process function 41 | 42 | 1.3.0, Jul 1, 2015 43 | 44 | * Added: Use browserslist to generate rem fallbacks only when needed 45 | 46 | 1.2.4, Apr 17, 2015 47 | 48 | * Fixed: generate fallbacks with a value starting with dot 49 | 50 | 1.2.3, Mar 27, 2015 51 | 52 | * Fix: copy and reduce decl.before, only if defined 53 | 54 | 1.2.2, Mar 27, 2015 55 | 56 | * Fix root-font size detection 57 | 58 | 1.2.1, Mar 23, 2015 59 | 60 | * Reduce line-breaks when inserting clone node 61 | 62 | 1.2.0, Feb 19, 2015 63 | 64 | * Add option `html` to disable root font-size detection 65 | * Fix root-font size defined with `calc` 66 | * Throw error when root font-size is invalid 67 | 68 | 1.1.1, Feb 5, 2015: 69 | 70 | * Fix root font-size detection 71 | 72 | 1.1.0, Jan 25, 2015: 73 | 74 | * PostCSS 4 75 | * Expose postcss processor 76 | 77 | 1.0.0, Nov 26, 2014: 78 | 79 | * Generate rem fallbacks only when needed 80 | * Updated to PostCSS v3.0 81 | * Get root font-size from CSS 82 | 83 | 0.1.4, March 6, 2014: Code optimization from AI. 84 | 0.1.3, Dec 14, 2013: Fix regex for < 0 values. 85 | 0.1.1, 0.1.2, Dec 14, 2013: Documentation improvements. 86 | 0.1.0, Dec 14, 2013: Initial release. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Robert Wierzbowski, contributors 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pixrem 2 | 3 | [![Build Status](https://travis-ci.org/robwierzbowski/node-pixrem.png?branch=master)](https://travis-ci.org/robwierzbowski/node-pixrem) 4 | 5 | [PostCSS](https://github.com/ai/postcss) plugin that generates pixel fallbacks for rem units. 6 | 7 | ## Installation 8 | 9 | `npm install --save pixrem` 10 | 11 | ## Usage 12 | 13 | Pixrem is a CSS post-processor that, given CSS and a root em value, returns CSS with pixel unit fallbacks or replacements. It's based on [browser data](http://caniuse.com/rem) so only needed fallbacks will be added. Basically, it's for IE8 or less, and for IE9 & IE10 in the `font` shorthand property and in pseudo-elements. 14 | 15 | ### Example 16 | 17 | ```js 18 | 'use strict'; 19 | var fs = require('fs'); 20 | var pixrem = require('pixrem'); 21 | var postcss = require('postcss'); 22 | 23 | var css = fs.readFileSync('main.css', 'utf8'); 24 | var processedCss = postcss([pixrem]).process(css).css; 25 | 26 | fs.writeFile('main.with-fallbacks.css', processedCss, function (err) { 27 | if (err) { 28 | throw err; 29 | } 30 | console.log('IE8, you\'re welcome.'); 31 | }); 32 | ``` 33 | 34 | Pixrem takes this: 35 | 36 | ```css 37 | .sky { 38 | margin: 2.5rem 2px 3em 100%; 39 | color: blue; 40 | } 41 | 42 | @media screen and (min-width: 20rem) { 43 | .leaf { 44 | margin-bottom: 1.333rem; 45 | font-size: 1.5rem; 46 | } 47 | } 48 | ``` 49 | 50 | And returns this: 51 | 52 | ```css 53 | .sky { 54 | margin: 80px 2px 3em 100%; 55 | margin: 2.5rem 2px 3em 100%; 56 | color: blue; 57 | } 58 | 59 | @media screen and (min-width: 20rem) { 60 | .leaf { 61 | margin-bottom: 1.333rem; 62 | font-size: 1.5rem; 63 | } 64 | } 65 | ``` 66 | 67 | ### Options 68 | 69 | Type: `Object | Null` 70 | Default: `{rootValue: 16, replace: false, atrules: false, html: true, browsers: 'ie <= 8', unitPrecision: 3}` 71 | 72 | - `rootValue` the root element font size. Can be `px`, `rem`, `em`, `%`, or unitless pixel value. Pixrem also tries to get the root font-size from CSS (`html` or `:root`) and overrides this option. Use `html` option to disable this behaviour. 73 | - `replace` replaces rules containing `rem`s instead of adding fallbacks. 74 | - `atrules` generates fallback in at-rules too (media-queries) 75 | - `html` overrides root font-size from CSS `html {}` or `:root {}` 76 | - `browsers` sets browser's range you want to target, based on [browserslist](https://github.com/ai/browserslist) 77 | - `unitPrecision` control the significant digits after the decimal point 78 | 79 | ## Contribute 80 | 81 | Report bugs and feature proposals in the [Github issue tracker](https://github.com/robwierzbowski/node-pixrem/issues). Run tests with `npm test`. In lieu of a formal styleguide, take care to maintain the existing coding style. 82 | 83 | ## License 84 | 85 | [MIT](http://en.wikipedia.org/wiki/MIT_License) 86 | 87 | 88 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/robwierzbowski/node-pixrem/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 89 | 90 | -------------------------------------------------------------------------------- /lib/pixrem.js: -------------------------------------------------------------------------------- 1 | var calc = require('reduce-css-calc'); 2 | var vendor = require('postcss/lib/vendor'); 3 | var postcss = require('postcss'); 4 | var browserslist = require('browserslist'); 5 | 6 | var REGEX = /(\d*\.?\d+)rem/ig; 7 | var BASE_FONT_SIZE = 16; 8 | var PROPS = /^(background-size|border-image|border-radius|box-shadow|clip-path|column|grid|mask|object|perspective|scroll|shape|size|stroke|transform)/; 9 | var VALUES = /(calc|gradient)\(/; 10 | 11 | module.exports = postcss.plugin('pixrem', function (opts) { 12 | 13 | opts = opts || {}; 14 | 15 | return function (css, result) { 16 | 17 | var options = {}; 18 | options.rootValue = (opts.rootValue !== undefined) ? opts.rootValue : BASE_FONT_SIZE; 19 | options.replace = (opts.replace !== undefined) ? opts.replace : false; 20 | options.atrules = (opts.atrules !== undefined) ? opts.atrules : false; 21 | options.html = (opts.html !== undefined) ? opts.html : true; 22 | options.unitPrecision = (opts.unitPrecision !== undefined) ? opts.unitPrecision : 3; 23 | options.browsers = (opts.browsers !== undefined) ? opts.browsers : 'ie <= 8'; 24 | options.browsers = browserslist(options.browsers); 25 | 26 | var isIElte8, isIEgte9, isIE9_10; 27 | if (detectBrowser(options.browsers, 'ie <= 8')) { 28 | isIElte8 = true; 29 | } 30 | if (detectBrowser(options.browsers, 'ie >= 9')) { 31 | isIEgte9 = true; 32 | } 33 | if (detectBrowser(options.browsers, 'ie 9, ie 10')) { 34 | isIE9_10 = true; 35 | } 36 | // no IE versions needed, skip 37 | if (!isIElte8 && !isIEgte9 && !isIE9_10) { return; } 38 | 39 | if (options.html) { 40 | // First, check root font-size 41 | css.walkRules(function (rule) { 42 | if (rule.parent && rule.parent.type === 'atrule') { return; } 43 | if (/^(html|:root)$/.test(rule.selectors)) { 44 | rule.walkDecls(function (decl) { 45 | if (decl.prop === 'font-size') { 46 | options.rootValue = decl.value; 47 | } else if (decl.prop === 'font' && decl.value.match(/\d/)) { 48 | options.rootValue = decl.value.match(/.*?([\d\.]*(em|px|rem|%|pt|pc))/)[1]; 49 | } 50 | }); 51 | } 52 | }); 53 | } 54 | 55 | css.walkRules(function (rule) { 56 | 57 | // if options.at-rules is false AND it's not IE9-10: skip @rules 58 | if (!options.atrules && !isIE9_10) { 59 | if (rule.type === 'atrule' || (rule.parent && rule.parent.type === 'atrule')) { return; } 60 | } 61 | 62 | var isPseudoElement = (rule.selector.search(/:(after|before)/gi) !== -1); 63 | 64 | rule.each(function (decl, i) { 65 | 66 | if (decl.type !== 'decl') { return; } 67 | 68 | var value = decl.value; 69 | 70 | if (value.indexOf('rem') !== -1) { 71 | 72 | var prop = vendor.unprefixed(decl.prop); 73 | var isFontShorthand = (prop === 'font'); 74 | var isSpecialCaseIE9_10 = (isIE9_10 && (isPseudoElement || isFontShorthand)); 75 | var isUseless = (VALUES.test(value) || PROPS.test(prop)); 76 | var isNotUseless = ((isIElte8 || !isIE9_10) && !isUseless); 77 | 78 | if ( isSpecialCaseIE9_10 || isNotUseless ) { 79 | 80 | value = value.replace(REGEX, function ($1) { 81 | return rounded(parseFloat($1) * toPx(options.rootValue, decl, result), options.unitPrecision) + 'px'; 82 | }); 83 | 84 | if (options.replace) { 85 | decl.value = value; 86 | } else { 87 | var clone = decl.clone({ value: value }); 88 | if (decl.raws.before) { 89 | clone.raws.before = decl.raws.before; 90 | decl.raws.before = reduceLineBreaks(decl.raws.before); 91 | } 92 | rule.insertBefore(i, clone); 93 | } 94 | 95 | } 96 | 97 | } 98 | 99 | }); 100 | 101 | }); 102 | 103 | }; 104 | 105 | }); 106 | 107 | // Detect if one browser from the browserQuery is in browsers 108 | function detectBrowser (browsers, browserQuery) { 109 | var b = false; 110 | browserQuery = browserslist(browserQuery); 111 | for (var i = 0; i < browsers.length; i++) { 112 | for (var j = 0; j < browserQuery.length; j++) { 113 | if (browsers[i] === browserQuery[j]) { 114 | b = true; 115 | break; 116 | } 117 | } 118 | if (b) { break; } 119 | } 120 | return b; 121 | } 122 | 123 | // Return a unitless pixel value from any root font-size value. 124 | function toPx (value, decl, result) { 125 | value = (typeof value === 'string' && value.indexOf('calc(') !== -1) ? calc(value) : value; 126 | var parts = /^(\d*\.?\d+)([a-zA-Z%]*)$/.exec(value); 127 | if (parts !== null) { 128 | var number = parts[1]; 129 | var unit = parts[2]; 130 | 131 | if (unit === 'px' || unit === '') { 132 | return parseFloat(number); 133 | } 134 | else if (unit === 'em' || unit === 'rem') { 135 | return parseFloat(number) * BASE_FONT_SIZE; 136 | } 137 | else if (unit === '%') { 138 | return (parseFloat(number) / 100) * BASE_FONT_SIZE; 139 | } else { 140 | // other units: vw, ex, ch, etc... 141 | result.warn('Unit cannot be used for conversion, so 16px is used.'); 142 | return BASE_FONT_SIZE; 143 | } 144 | } else { 145 | throw decl.error('Root font-size is invalid', {plugin: 'pixrem'}); 146 | } 147 | } 148 | 149 | // Reduce line breaks 150 | function reduceLineBreaks (value) { 151 | return value.replace(/(\r*\n|\r)+/g, '$1'); 152 | } 153 | 154 | // Round values based on precision 155 | // rounded down to match webkit and opera behavior: 156 | // http://tylertate.com/blog/2012/01/05/subpixel-rounding.html 157 | function rounded (value, precision) { 158 | precision = Math.pow(10, precision); 159 | return Math.floor(value * precision) / precision; 160 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pixrem", 3 | "description": "A CSS post-processor that generates pixel fallbacks for rem units.", 4 | "version": "5.0.0", 5 | "homepage": "https://github.com/robwierzbowski/node-pixrem", 6 | "author": "Rob Wierzbowski (http://robwierzbowski.com)", 7 | "repository": { 8 | "type": "git", 9 | "url": "git://github.com/robwierzbowski/node-pixrem.git" 10 | }, 11 | "bugs": "https://github.com/robwierzbowski/node-pixrem/issues", 12 | "licenses": [ 13 | { 14 | "type": "BSD-3-Clause" 15 | } 16 | ], 17 | "main": "lib/pixrem.js", 18 | "engines": { 19 | "node": ">=4.0.0", 20 | "npm": ">=1.2.10" 21 | }, 22 | "scripts": { 23 | "test": "mocha" 24 | }, 25 | "dependencies": { 26 | "browserslist": "^4.3.6", 27 | "postcss": "^7.0.7", 28 | "reduce-css-calc": "^2.1.5" 29 | }, 30 | "devDependencies": { 31 | "mocha": "^2.3.2" 32 | }, 33 | "keywords": [ 34 | "css", 35 | "postcss", 36 | "postcss-plugin", 37 | "rem", 38 | "parser", 39 | "postproccessor", 40 | "responsive" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'); 4 | var assert = require("assert"); 5 | var pixrem = require('../lib/pixrem'); 6 | var postcss = require('postcss'); 7 | 8 | var css = '.rule { font-size: 2rem }'; 9 | 10 | describe('pixrem', function () { 11 | 12 | it('should generate fallbacks using default settings', function () { 13 | var expected = '.rule { font-size: 32px; font-size: 2rem }'; 14 | var processed = postcss([pixrem]).process(css).css; 15 | assert.equal(processed, expected); 16 | }); 17 | 18 | it('should default to 16 when undefined', function () { 19 | var expected = '.rule { font-size: 32px; font-size: 2rem }'; 20 | var processed = postcss([pixrem({rootValue: undefined})]).process(css).css; 21 | assert.equal(processed, expected); 22 | }); 23 | 24 | it('should generate fallbacks with a pixel root em value', function () { 25 | var expected = '.rule { font-size: 40px; font-size: 2rem }'; 26 | var processed = postcss([pixrem({rootValue: '20px'})]).process(css).css; 27 | assert.equal(processed, expected); 28 | }); 29 | 30 | it('should generate fallbacks with a em root em value', function () { 31 | var expected = '.rule { font-size: 48px; font-size: 2rem }'; 32 | var processed = postcss([pixrem({rootValue: '1.5em'})]).process(css).css; 33 | assert.equal(processed, expected); 34 | }); 35 | 36 | it('should generate fallbacks with a rem root em value', function () { 37 | var expected = '.rule { font-size: 56px; font-size: 2rem }'; 38 | var processed = postcss([pixrem({rootValue: '1.75rem'})]).process(css).css; 39 | assert.equal(processed, expected); 40 | }); 41 | 42 | it('should generate fallbacks with a percent root em value', function () { 43 | var expected = '.rule { font-size: 48px; font-size: 2rem }'; 44 | var processed = postcss([pixrem({rootValue: '150%'})]).process(css).css; 45 | assert.equal(processed, expected); 46 | }); 47 | 48 | it('should generate fallbacks with a unitless root em value', function () { 49 | var expected = '.rule { font-size: 36px; font-size: 2rem }'; 50 | var processed = postcss([pixrem({rootValue: '18'})]).process(css).css; 51 | assert.equal(processed, expected); 52 | }); 53 | 54 | it('should generate fallbacks with a vw root em value', function () { 55 | var expected = '.rule { font-size: 32px; font-size: 2rem }'; 56 | var processed = postcss([pixrem({rootValue: '.625vw'})]).process(css).css; 57 | assert.equal(processed, expected); 58 | }); 59 | 60 | it('should warn when using browser-dependent unit', function (done) { 61 | var expected = '.rule { font-size: 32px; font-size: 2rem }'; 62 | var processed = postcss([pixrem({rootValue: '1vw'})]).process(css).then(function (result) { 63 | var warnings = result.warnings(); 64 | assert.deepEqual(warnings, [{type: 'warning', text: 'Unit cannot be used for conversion, so 16px is used.', plugin: 'pixrem'}]); 65 | done(); 66 | }).catch(done); 67 | }); 68 | 69 | it('should generate fallbacks with a value starting with dot', function () { 70 | var expected = '.rule { font-size: 16px; font-size: 2rem }'; 71 | var processed = postcss([pixrem({rootValue: '.5em'})]).process(css).css; 72 | assert.equal(processed, expected); 73 | }); 74 | 75 | it('should replace rules with fallbacks when option.replace is true', function () { 76 | var expected = '.rule { font-size: 40px }'; 77 | var processed = postcss([pixrem({rootValue: '20px', replace: true})]).process(css).css; 78 | assert.equal(processed, expected); 79 | }); 80 | 81 | it('should round values based on default precision', function () { 82 | var expected = '.rule { font-size: 36.032px; font-size: 2rem }'; 83 | var processed = postcss([pixrem({rootValue: '1.126em'})]).process(css).css; 84 | assert.equal(processed, expected); 85 | }); 86 | 87 | it('should return integer when precision is 0', function () { 88 | var expected = '.rule { font-size: 36px; font-size: 2rem }'; 89 | var processed = postcss([pixrem({rootValue: '1.126em', unitPrecision: 0})]).process(css).css; 90 | assert.equal(processed, expected); 91 | }); 92 | 93 | it('should return integer rounded down', function () { 94 | var expected = '.rule { font-size: 36px; font-size: 2rem }'; 95 | var processed = postcss([pixrem({rootValue: '1.156em', unitPrecision: 0})]).process(css).css; 96 | assert.equal(processed, expected); 97 | }); 98 | 99 | it('should handle < 1 values and values without a leading 0', function () { 100 | var css = '.rule { margin: 0.5rem .5rem 0rem -2rem }'; 101 | var expected = '.rule { margin: 8px 8px 0px -32px; margin: 0.5rem .5rem 0rem -2rem }'; 102 | var processed = postcss([pixrem]).process(css).css; 103 | assert.equal(processed, expected); 104 | }); 105 | 106 | it('should generate default fallback with an inline sourcemap', function () { 107 | var expected = '.rule { font-size: 32px; font-size: 2rem }\n/*# sourceMappingURL=whatever.css.map *\/'; 108 | var processed = postcss([pixrem]).process(css, { 109 | map: { 'inline': false }, 110 | to: 'whatever.css' 111 | }); 112 | assert.equal(processed, expected); 113 | }); 114 | 115 | it('should not convert rem in at-rules', function () { 116 | var css = '@media screen { .rule { font-size: 2rem } } @keyframes name { from { font-size: 2rem } }'; 117 | var processed = postcss([pixrem]).process(css).css; 118 | assert.equal(processed, css); 119 | }); 120 | 121 | it('should convert rem in at-rules if options is true', function () { 122 | var css = '@media screen { .rule { font-size: 2rem } }'; 123 | var expected = '@media screen { .rule { font-size: 32px; font-size: 2rem } }'; 124 | var processed = postcss([pixrem({atrules: true})]).process(css).css; 125 | assert.equal(processed, expected); 126 | }); 127 | 128 | it('should convert rem in at-rules for IE9 hacks', function () { 129 | var css = '@media screen { .rule { font-size: 2rem } .rule::after { font-size: 2rem } }'; 130 | var expected = '@media screen { .rule { font-size: 2rem } .rule::after { font-size: 32px; font-size: 2rem } }'; 131 | var processed = postcss([pixrem({browsers: 'ie 9'})]).process(css).css; 132 | assert.equal(processed, expected); 133 | }); 134 | 135 | it('should not convert rem in nested at-rules', function () { 136 | var css = '@media screen { .rule { font-size: 2rem } @media screen { .rule { font-size: 2rem } @media screen { .rule { font-size: 2rem } } } }'; 137 | var processed = postcss([pixrem]).process(css).css; 138 | assert.equal(processed, css); 139 | }); 140 | 141 | it('should not convert rem in unsupported feature (value)', function () { 142 | var css = '.rule { width: calc(100% - 2rem); background: linear-gradient(red 2rem, blue) }'; 143 | var processed = postcss([pixrem]).process(css).css; 144 | assert.equal(processed, css); 145 | }); 146 | 147 | it('should not convert rem in unsupported feature (property)', function () { 148 | var css = '.rule { transform: translate(2rem) }'; 149 | var processed = postcss([pixrem]).process(css).css; 150 | assert.equal(processed, css); 151 | }); 152 | 153 | it('should not convert rem in unsupported feature (with prefixes)', function () { 154 | var css = '.rule { width: -webkit-calc(100% - 2rem); width: calc(100% - 2rem); -ms-transform: translate(2rem) }'; 155 | var processed = postcss([pixrem]).process(css).css; 156 | assert.equal(processed, css); 157 | }); 158 | 159 | it('should use default root font-size as defined in CSS', function () { 160 | var css = 'html { font-size: 62.5% } .rule { font-size: 2rem; }'; 161 | var expected = 'html { font-size: 62.5% } .rule { font-size: 20px; font-size: 2rem; }'; 162 | var processed = postcss([pixrem]).process(css).css; 163 | assert.equal(processed, expected); 164 | }); 165 | 166 | it('should use default root font-size from font declaration', function () { 167 | var css = '.rule { font-size: 2rem; } :root { font: italic 100 20px/24px sans-serif }'; 168 | var expected = '.rule { font-size: 40px; font-size: 2rem; } :root { font: italic 100 20px/24px sans-serif }'; 169 | var processed = postcss([pixrem]).process(css).css; 170 | assert.equal(processed, expected); 171 | }); 172 | 173 | it('should detect root font-size only if targeted', function () { 174 | var css = ':root a { font-size: 10px } .rule { font-size: 2rem; }'; 175 | var expected = ':root a { font-size: 10px } .rule { font-size: 32px; font-size: 2rem; }'; 176 | var processed = postcss([pixrem]).process(css).css; 177 | assert.equal(processed, expected); 178 | }); 179 | 180 | it('should use root font-size defined with calc', function () { 181 | var css = 'html { font-size: calc(.625em * 1) } .rule { font-size: 2rem; }'; 182 | var expected = 'html { font-size: calc(.625em * 1) } .rule { font-size: 20px; font-size: 2rem; }'; 183 | var processed = postcss([pixrem]).process(css).css; 184 | assert.equal(processed, expected); 185 | }); 186 | 187 | it('should not use root font-size in MQ', function () { 188 | var css = 'html { font-size: 10px } @media screen { html { font-size: 20px } } .rule { font-size: 2rem; }'; 189 | var expected = 'html { font-size: 10px } @media screen { html { font-size: 20px } } .rule { font-size: 20px; font-size: 2rem; }'; 190 | var processed = postcss([pixrem]).process(css).css; 191 | assert.equal(processed, expected); 192 | }); 193 | 194 | it('should run through font shorthand without root size', function () { 195 | var css = 'html { font: inherit } .rule { font-size: 2rem; }'; 196 | var expected = 'html { font: inherit } .rule { font-size: 32px; font-size: 2rem; }'; 197 | var processed = postcss([pixrem]).process(css).css; 198 | assert.equal(processed, expected); 199 | }); 200 | 201 | it('should not use root font-size when option is set', function () { 202 | var css = 'html { font-size: 10px } .rule { font-size: 2rem; }'; 203 | var expected = 'html { font-size: 10px } .rule { font-size: 32px; font-size: 2rem; }'; 204 | var processed = postcss([pixrem({html: false})]).process(css).css; 205 | assert.equal(processed, expected); 206 | }); 207 | 208 | it('should throw error when root font-size is invalid', function (done) { 209 | var css = 'html { font-size: calc(1em + 2px) } .rule { font-size: 2rem; }'; 210 | postcss([pixrem]).process(css).then(function () { 211 | done('should not run'); 212 | }).catch(function (err) { 213 | assert.equal(err.name, 'CssSyntaxError'); 214 | assert.equal(err.reason, 'Root font-size is invalid'); 215 | done(); 216 | }).catch(done); 217 | }); 218 | 219 | it('should reduce line-breaks when inserting new node', function () { 220 | var css = '.rule{\n\tcolor:red;\n\n\tfont-size:2rem;\n}'; 221 | var expected = '.rule{\n\tcolor:red;\n\n\tfont-size:32px;\n\tfont-size:2rem;\n}'; 222 | var processed = postcss([pixrem]).process(css).css; 223 | assert.equal(processed, expected); 224 | }); 225 | 226 | it('should reduce and keep windows line-breaks', function () { 227 | var css = '.rule{\r\n\tcolor:red;\r\n\r\n\tfont-size:2rem;\r\n}'; 228 | var expected = '.rule{\r\n\tcolor:red;\r\n\r\n\tfont-size:32px;\r\n\tfont-size:2rem;\r\n}'; 229 | var processed = postcss([pixrem]).process(css).css; 230 | assert.equal(processed, expected); 231 | }); 232 | 233 | it('should reduce and keep linux line-breaks', function () { 234 | var css = '.rule{\r\tcolor:red;\r\r\tfont-size:2rem;\r}'; 235 | var expected = '.rule{\r\tcolor:red;\r\r\tfont-size:32px;\r\tfont-size:2rem;\r}'; 236 | var processed = postcss([pixrem]).process(css).css; 237 | assert.equal(processed, expected); 238 | }); 239 | 240 | it('should not reduce line-breaks when replacing node', function () { 241 | var css = '.rule{\n\tcolor:red;\n\n\tfont-size:2rem;\n}'; 242 | var expected = '.rule{\n\tcolor:red;\n\n\tfont-size:32px;\n}'; 243 | var processed = postcss([pixrem({replace: true})]).process(css).css; 244 | assert.equal(processed, expected); 245 | }); 246 | 247 | it('should not add fallback when IE8- are not in scope', function () { 248 | var css = '.rule{width: 2rem}'; 249 | var expected = '.rule{width: 2rem}'; 250 | var processed = postcss([pixrem({browsers: 'firefox 28'})]).process(css).css; 251 | assert.equal(processed, expected); 252 | }); 253 | 254 | it('should add fallback when only IE8 is in scope', function () { 255 | var css = '.rule{width: 2rem}'; 256 | var expected = '.rule{width: 32px;width: 2rem}'; 257 | var processed = postcss([pixrem({browsers: 'ie 8'})]).process(css).css; 258 | assert.equal(processed, expected); 259 | }); 260 | 261 | it('should add fallback when IE8 is in scope', function () { 262 | var css = '.rule{width: 2rem}'; 263 | var expected = '.rule{width: 32px;width: 2rem}'; 264 | var processed1 = postcss([pixrem({browsers: 'ie 8'})]).process(css).css; 265 | var processed2 = postcss([pixrem({browsers: 'ie >= 8'})]).process(css).css; 266 | var processed3 = postcss([pixrem({browsers: 'ie <= 8'})]).process(css).css; 267 | assert.equal(processed1, processed2); 268 | assert.equal(processed2, processed3); 269 | }); 270 | 271 | it('should add fallback when only IE6 is in scope', function () { 272 | var css = '.rule{width: 2rem}'; 273 | var expected = '.rule{width: 32px;width: 2rem}'; 274 | var processed = postcss([pixrem({browsers: 'ie 6'})]).process(css).css; 275 | assert.equal(processed, expected); 276 | }); 277 | 278 | it('should add fallback only for font and pseudo-element when IE9 is in scope', function () { 279 | var css = '.rule{width: 2rem;font: bold 2rem sans-serif}.rule::after{width: 2rem}'; 280 | var expected = '.rule{width: 2rem;font: bold 32px sans-serif;font: bold 2rem sans-serif}.rule::after{width: 32px;width: 2rem}'; 281 | var processed = postcss([pixrem({browsers: 'ie 9'})]).process(css).css; 282 | assert.equal(processed, expected); 283 | }); 284 | 285 | }); 286 | --------------------------------------------------------------------------------