├── .codeclimate.yml ├── .editorconfig ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── index.js ├── package.json └── test.js /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | duplication: 4 | enabled: true 5 | config: 6 | languages: 7 | - ruby 8 | - javascript 9 | - python 10 | - php 11 | eslint: 12 | enabled: true 13 | fixme: 14 | enabled: true 15 | ratings: 16 | paths: 17 | - "**.inc" 18 | - "**.js" 19 | - "**.jsx" 20 | - "**.module" 21 | - "**.php" 22 | - "**.py" 23 | - "**.rb" 24 | exclude_paths: [] 25 | engines: 26 | # ... CONFIG CONTENT ... 27 | eslint: 28 | enabled: true 29 | # ... CONFIG CONTENT ... 30 | checks: 31 | global-require: 32 | enabled: false 33 | # ... CONFIG CONTENT ... 34 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.{json,yml}] 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | package-lock.json -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | 3 | node_modules/ 4 | npm-debug.log 5 | 6 | test.js 7 | .travis.yml 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 4 4 | - 5 5 | - 6 6 | - 7 7 | - 8 8 | addons: 9 | code_climate: 10 | repo_token: 2260ae001cc4170569f047c63271773bb5e3b72e8d29be2e9006d40377132ed1 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2.0 2 | * support Postcss v6 3 | * support nodejs versions 4-8 4 | * bump misc dependency versions 5 | 6 | ## 1.4 7 | * add postcs-vmin to support vmin in IE9 8 | 9 | ## 1.3 10 | * add postcss-nth-child-fix 11 | 12 | ## 1.2 13 | * available presets: recommended, safe, fixes-only, fallbacks-only, enable-all and disable-all 14 | 15 | ## 1.1 16 | * Restructuring, option 'mode' changed to 'preset' 17 | 18 | ## 1.0 19 | * Initial release 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright 2016 Matthias Müller 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PostCSS Fixes [![Build Status][ci-img]][ci] [![Code Climate](https://codeclimate.com/github/MattDiMu/postcss-fixes/badges/gpa.svg)](https://codeclimate.com/github/MattDiMu/postcss-fixes) 2 | 3 | [PostCSS]: https://github.com/postcss/postcss 4 | [ci-img]: https://travis-ci.org/MattDiMu/postcss-fixes.svg 5 | [ci]: https://travis-ci.org/MattDiMu/postcss-fixes 6 | 7 | [PostCSS] pack to fix known Browser Bugs, making it easier to write your CSS according to the official W3C Syntax. Additionally it adds safe fallbacks. 8 | 9 | [postcss-fixes](https://github.com/MattDiMu/postcss-fixes) differs from [cssnext](https://github.com/MoOx/postcss-cssnext) by doing only transformations for stable CSS Features, whereas cssnext is more progressively tries to implement features, which aren't official W3C recommendations yet and could therefore change/break in the future. Another alternative is [oldie](https://github.com/jonathantneal/oldie), which is Internet Explorer only, however. 10 | 11 | 12 | ## A few examples 13 | ```css 14 | :nth-child(n)::before { 15 | flex: 1; 16 | opacity: .5; 17 | height: 2.5rem; 18 | width: 10vmin; 19 | } 20 | ``` 21 | 22 | ```css 23 | :nth-child(1n):before { 24 | flex: 1 1 0%; /* fix some flexbox issues */ 25 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; /* opacity for IE */ 26 | opacity: .5; 27 | height: 40px; /* rem to px fallback */ 28 | height: 2.5rem; 29 | width: 10vm; 30 | width: 10vmin; 31 | } 32 | ``` 33 | 34 | ## Used Plugins 35 | Hint: An opinionated config for these plugins is used, to make them more future-safe 36 | * [pixrem](https://github.com/robwierzbowski/node-pixrem) 37 | * [postcss-calc](https://github.com/postcss/postcss-calc) 38 | * [postcss-flexbugs-fixes](https://github.com/luisrudge/postcss-flexbugs-fixes) (also in 'safe' mode) 39 | * [postcss-pseudoelements](https://github.com/axa-ch/postcss-pseudoelements) (also in 'safe' mode) 40 | * [postcss-unopacity](https://github.com/jonathantneal/postcss-unopacity) 41 | * [postcss-unroot](https://github.com/jonathantneal/postcss-unroot) 42 | * [postcss-nth-child-fix](https://github.com/MattDiMu/postcss-nth-child-fix) 43 | * [postcss-vmin](https://github.com/iamvdo/postcss-vmin) 44 | 45 | 46 | ### Recommended Usage 47 | [postcss-fixes](https://github.com/MattDiMu/postcss-fixes) is recommended to be used in conjunction with [autoprefixer](https://github.com/postcss/autoprefixer) and [cssnano](https://github.com/ben-eb/cssnano) (optimizations) 48 | ```js 49 | /* for developement */ 50 | postcss([ 51 | require('postcss-fixes')(), 52 | require('autoprefixer')() 53 | ]) 54 | 55 | /* for production */ 56 | postcss([ 57 | require('postcss-fixes')(), 58 | require('autoprefixer')(), 59 | require('cssnano')({ 60 | 'safe': true, // I would recommend using cssnano only in safe mode 61 | 'calc': false // calc is no longer necessary, as it is already done by postcss-fixes due to precision rounding reasons 62 | }) 63 | ]) 64 | ``` 65 | See [PostCSS](https://github.com/postcss/postcss) docs for examples for your environment (e.g. if you are using a task runner like grunt, gulp, broccoli, webpack, etc.). 66 | 67 | 68 | ## Options 69 | ### `preset` 70 | * `recommended` (default) 71 | * `safe` 72 | * `fixes-only` 73 | * `fallbacks-only` 74 | * `enable-all` 75 | * `disable-all` 76 | 77 | This would look like this: 78 | 79 | ```js 80 | postcss([ 81 | require('postcss-fixes')({ preset: 'safe' }) // do only very safe transformations 82 | ]) 83 | ``` 84 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var postcss = require('postcss'); 2 | 3 | 4 | var presets = [ 5 | 'recommended', // default 6 | 'safe', 7 | 'fixes-only', 8 | 'fallbacks-only', 9 | 'enable-all', 10 | 'disable-all' 11 | ]; 12 | var defaultPreset = 'recommended'; 13 | 14 | var plugins = [ 15 | { 16 | id: 'postcss-pseudoelements', 17 | plugin: require('postcss-pseudoelements'), 18 | options: {}, 19 | isSafe: true, 20 | isRecommended: true, 21 | isFallback: false 22 | }, 23 | { 24 | id: 'postcss-flexbugs-fixes', 25 | plugin: require('postcss-flexbugs-fixes'), 26 | options: {}, 27 | isSafe: true, 28 | isRecommended: true, 29 | isFallback: false 30 | }, 31 | { 32 | /* 33 | theoretically unsafe, as a browser might calculate 34 | a different precision of decimals, but in practice 35 | we want the same precision in all browsers anway. 36 | therefore we recommmend using this even in development mode 37 | */ 38 | id: 'postcss-calc', 39 | plugin: require('postcss-calc'), 40 | options: {}, 41 | isSafe: false, 42 | isRecommended: true, 43 | isFallback: false 44 | }, 45 | { 46 | id: 'postcss-unroot', 47 | plugin: require('postcss-unroot'), 48 | options: {}, 49 | isSafe: false, 50 | isRecommended: true, 51 | isFallback: true 52 | }, 53 | { 54 | id: 'postcss-unopacity', 55 | plugin: require('postcss-unopacity'), 56 | options: { method: 'copy', prefixed: true }, 57 | isSafe: false, 58 | isRecommended: true, 59 | isFallback: true 60 | }, 61 | { 62 | id: 'pixrem', 63 | plugin: require('pixrem'), 64 | options: { 65 | replace: false, 66 | html: true, // root value autodetection 67 | unitPrecision: 5 68 | }, 69 | isSafe: false, 70 | isRecommended: true, 71 | isFallback: true 72 | }, 73 | { 74 | id: 'postcss-nth-child-fix', 75 | plugin: require('postcss-nth-child-fix'), 76 | options: {}, 77 | isSafe: true, 78 | isRecommended: true, 79 | isFallback: false 80 | }, 81 | { 82 | id: 'postcss-vmin', 83 | plugin: require('postcss-vmin'), 84 | options: {}, 85 | isSafe: true, 86 | isRecommended: true, 87 | isFallback: false 88 | } 89 | ]; 90 | 91 | /* 92 | currently not used plugins - reason why 93 | postcss-unnth - potentially bloats files too much, not worth the few edge cases IMO 94 | postcss-unrgba - when using the 'clone'-method to preserve the desired color, it gets hard to create a custom fallback 95 | */ 96 | 97 | function isSafe(elem) { return elem.isSafe; } // eslint-disable-line brace-style 98 | function isRecommended(elem) { return elem.isRecommended; } // eslint-disable-line brace-style 99 | function isFallback(elem) { return elem.isFallback; } // eslint-disable-line brace-style 100 | function isFix(elem) { return !elem.isFallback; } // eslint-disable-line brace-style 101 | 102 | 103 | function evalPluginsFromPreset(preset) { 104 | var pluginsArr = plugins; 105 | if (preset === 'enable-all') { 106 | return pluginsArr; 107 | } else if (preset === 'disable-all') { 108 | return []; 109 | } else if (preset === 'fixes-only') { 110 | return pluginsArr.filter(isFix); 111 | } else if (preset === 'fallbacks-only') { 112 | return pluginsArr.filter(isFallback); 113 | } else if (preset === 'safe') { 114 | return pluginsArr.filter(isSafe); 115 | } else { // recommended 116 | return pluginsArr.filter(isRecommended); 117 | } 118 | 119 | } 120 | 121 | 122 | module.exports = postcss.plugin('postcss-fixes', opts => { 123 | opts = opts || {}; 124 | if (opts.mode && opts.mode === 'safe') console.warn('[postcss-fixes] option "mode" was renamed to "preset". '); 125 | 126 | var preset = defaultPreset; 127 | if (opts.preset) { 128 | if (presets.indexOf(opts.preset) > -1) { 129 | preset = opts.preset; 130 | } else { 131 | console.warn('[postcss-fixes] option "preset": "' + opts.preset + '" is invalid and will be ignored'); 132 | } 133 | } 134 | 135 | var usedPlugins = evalPluginsFromPreset(preset); 136 | 137 | var postcssInstance = postcss(); 138 | 139 | usedPlugins.forEach(plugin => { 140 | postcssInstance.use(plugin.plugin(plugin.options)); 141 | }); 142 | 143 | return postcssInstance; 144 | }); 145 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "postcss-fixes", 3 | "version": "3.0.0", 4 | "type": "commonjs", 5 | "description": "PostCSS plugin pack to fix known Browser Bugs.", 6 | "keywords": [ 7 | "postcss", 8 | "css", 9 | "postcss-plugin", 10 | "browserbugs", 11 | "bugfixes" 12 | ], 13 | "author": "Matthias Müller ", 14 | "license": "MIT", 15 | "repository": "MattDiMu/postcss-fixes", 16 | "bugs": { 17 | "url": "https://github.com/MattDiMu/postcss-fixes/issues" 18 | }, 19 | "homepage": "https://github.com/MattDiMu/postcss-fixes", 20 | "dependencies": { 21 | "lodash": "^4.17.21", 22 | "pixrem": "^3.0.2", 23 | "postcss": "^6.0.23", 24 | "postcss-calc": "^6.0.2", 25 | "postcss-flexbugs-fixes": "^3.3.1", 26 | "postcss-nth-child-fix": "^2.0.0", 27 | "postcss-pseudoelements": "^3.0.0", 28 | "postcss-unopacity": "^1.0.1", 29 | "postcss-unroot": "^1.0.2", 30 | "postcss-vmin": "^3.0.0" 31 | }, 32 | "devDependencies": { 33 | "ava": "^3.15.0", 34 | "eslint": "^3.19.0", 35 | "eslint-config-postcss": "^2.0.2" 36 | }, 37 | "scripts": { 38 | "test": "ava && eslint *.js", 39 | "test:ava": "ava", 40 | "test:eslint": "eslint *.js" 41 | }, 42 | "eslintConfig": { 43 | "extends": "eslint-config-postcss/es5", 44 | "rules": { 45 | "max-len": 0 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss'); 2 | const test = require('ava'); 3 | const plugin = require('./index.js'); 4 | 5 | function run(t, input, output, opts = { }) { 6 | return postcss([ plugin(opts) ]).process(input) 7 | .then( result => { 8 | t.deepEqual(result.css, output); 9 | t.deepEqual(result.warnings().length, 0); 10 | }); 11 | } 12 | 13 | 14 | test('pseudo-selectors adapted, no config given', t => { 15 | return run(t, 'a::before{ }', 'a:before{ }', {}); 16 | }); 17 | 18 | test('pseudo-selectors adapted, default config', t => { 19 | return run(t, 'a::before{ }', 'a:before{ }', { }); 20 | }); 21 | 22 | test('opacity fallback, safe mode', t => { 23 | return run(t, '.class{opacity: .5;}', '.class{opacity: .5;}', { preset: 'safe' }); 24 | }); 25 | 26 | test('opacity fallback, default config', t => { 27 | return run(t, '.class{opacity: .5;}', '.class{-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";opacity: .5;}', { }); 28 | }); 29 | 30 | test('rem to px fallback, default config', t => { 31 | return run(t, 'main{font-size:2.5rem;}', 'main{font-size:40px;font-size:2.5rem;}', { }); 32 | }); 33 | 34 | test('rem to px fallback with custom root font size, default config', t => { 35 | return run(t, 'main{font-size:2.5rem;}html{font-size:10px;}', 'main{font-size:25px;font-size:2.5rem;}html{font-size:10px;}', { }); 36 | }); 37 | 38 | test('change nth-child(n) to 1n', t => { 39 | return run(t, '*:nth-child(n){font-size:2.5rem;}', '*:nth-child(1n){font-size:40px;font-size:2.5rem;}', { }); 40 | }); 41 | 42 | test('fallback for vmin', t => { 43 | return run(t, '*:nth-child(n){height:25vmin;}', '*:nth-child(1n){height:25vm;height:25vmin;}', { }); 44 | }); 45 | --------------------------------------------------------------------------------