├── .editorconfig ├── .eslintrc ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── index.js ├── package.json └── test ├── fixtures ├── aspect-ratio.css ├── aspect-ratio.expect.css ├── basic.css ├── basic.expect.css └── basic.width.expect.css └── index.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false 12 | 13 | [*.{json,yml}] 14 | indent_size = 2 15 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-shadow-restricted-names": [2], 4 | "computed-property-spacing": [2], 5 | "no-empty-character-class": [2], 6 | "no-irregular-whitespace": [2], 7 | "no-unexpected-multiline": [2], 8 | "no-multiple-empty-lines": [2], 9 | "space-return-throw-case": [2], 10 | "no-constant-condition": [2], 11 | "no-extra-boolean-cast": [2], 12 | "no-inner-declarations": [2], 13 | "no-this-before-super": [2], 14 | "no-array-constructor": [2], 15 | "object-curly-spacing": [2, "always"], 16 | "no-floating-decimal": [2], 17 | "no-warning-comments": [2], 18 | "handle-callback-err": [2], 19 | "no-unneeded-ternary": [2], 20 | "operator-assignment": [2], 21 | "space-before-blocks": [2], 22 | "no-native-reassign": [2], 23 | "no-trailing-spaces": [2], 24 | "operator-linebreak": [2, "after"], 25 | "consistent-return": [2], 26 | "no-duplicate-case": [2], 27 | "no-invalid-regexp": [2], 28 | "no-negated-in-lhs": [2], 29 | "constructor-super": [2], 30 | "no-nested-ternary": [0], 31 | "no-extend-native": [2], 32 | "block-scoped-var": [2], 33 | "no-control-regex": [2], 34 | "no-sparse-arrays": [2], 35 | "no-throw-literal": [2], 36 | "no-return-assign": [2], 37 | "no-const-assign": [2], 38 | "no-class-assign": [2], 39 | "no-extra-parens": [2], 40 | "no-regex-spaces": [2], 41 | "no-implied-eval": [2], 42 | "no-useless-call": [2], 43 | "no-self-compare": [2], 44 | "no-octal-escape": [2], 45 | "no-new-wrappers": [2], 46 | "no-process-exit": [2], 47 | "no-catch-shadow": [2], 48 | "linebreak-style": [2], 49 | "space-infix-ops": [2], 50 | "space-unary-ops": [2], 51 | "no-func-assign": [2], 52 | "no-unreachable": [2], 53 | "accessor-pairs": [2], 54 | "no-empty-label": [2], 55 | "no-fallthrough": [2], 56 | "no-path-concat": [2], 57 | "no-new-require": [2], 58 | "no-spaced-func": [2], 59 | "no-unused-vars": [2], 60 | "spaced-comment": [2], 61 | "no-delete-var": [2], 62 | "comma-spacing": [2], 63 | "no-extra-semi": [2], 64 | "no-extra-bind": [2], 65 | "arrow-spacing": [2], 66 | "prefer-spread": [2], 67 | "no-new-object": [2], 68 | "no-multi-str": [2], 69 | "semi-spacing": [2], 70 | "no-lonely-if": [2], 71 | "dot-notation": [2], 72 | "dot-location": [2, "property"], 73 | "comma-dangle": [2, "never"], 74 | "no-dupe-args": [2], 75 | "no-dupe-keys": [2], 76 | "no-ex-assign": [2], 77 | "no-obj-calls": [2], 78 | "valid-typeof": [2], 79 | "default-case": [2], 80 | "no-redeclare": [2], 81 | "no-div-regex": [2], 82 | "no-sequences": [2], 83 | "no-label-var": [2], 84 | "comma-style": [2], 85 | "brace-style": [2], 86 | "no-debugger": [2], 87 | "quote-props": [0], 88 | "no-iterator": [2], 89 | "no-new-func": [2], 90 | "key-spacing": [2, { "align": "value" }], 91 | "complexity": [2], 92 | "new-parens": [2], 93 | "no-eq-null": [2], 94 | "no-bitwise": [0], 95 | "wrap-iife": [2], 96 | "no-caller": [2], 97 | "use-isnan": [2], 98 | "no-labels": [2], 99 | "no-shadow": [2], 100 | "camelcase": [2], 101 | "eol-last": [2], 102 | "no-octal": [2], 103 | "no-empty": [2], 104 | "no-alert": [2], 105 | "no-proto": [2], 106 | "no-undef": [2], 107 | "no-eval": [2], 108 | "no-with": [2], 109 | "no-void": [2], 110 | "new-cap": [2], 111 | "eqeqeq": [2], 112 | "no-new": [2], 113 | "quotes": [2, "single"], 114 | "indent": [2, "tab"], 115 | "semi": [2, "always"], 116 | "yoda": [2, "never"] 117 | }, 118 | "env": { 119 | "mocha": true, 120 | "node": true 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | test/fixtures/*.actual.css 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - stable 5 | - "0.12" 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.2 (2015-10-24) 2 | 3 | - Updated: Documentation 4 | 5 | ## 1.0.1 (2015-10-24) 6 | 7 | - Updated: Tests and documentation 8 | 9 | ## 1.0.0 (2015-08-26) 10 | 11 | - Added: Initial release 12 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | You want to help? You rock! Now, take a moment to be sure your contributions make sense to everyone else. 2 | 3 | ## Reporting Issues 4 | 5 | Found a problem? Want a new feature? 6 | 7 | - See if your issue or idea has [already been reported]. 8 | - Provide a [reduced test case] or a [live example]. 9 | 10 | Remember, a bug is a _demonstrable problem_ caused by _our_ code. 11 | 12 | ## Submitting Pull Requests 13 | 14 | Pull requests are the greatest contributions, so be sure they are focused in scope, and do avoid unrelated commits. 15 | 16 | 1. To begin, [fork this project], clone your fork, and add our upstream. 17 | ```bash 18 | # Clone your fork of the repo into the current directory 19 | git clone https://github.com//postcss-unmq 20 | # Navigate to the newly cloned directory 21 | cd postcss-unmq 22 | # Assign the original repo to a remote called "upstream" 23 | git remote add upstream https://github.com/jonathantneal/postcss-unmq 24 | # Install the tools necessary for development 25 | npm install 26 | ``` 27 | 28 | 2. Create a branch for your feature or fix: 29 | ```bash 30 | # Move into a new branch for a feature 31 | git checkout -b feature/thing 32 | ``` 33 | ```bash 34 | # Move into a new branch for a fix 35 | git checkout -b fix/something 36 | ``` 37 | 38 | 3. Be sure your code follows our practices. 39 | ```bash 40 | # Test current code 41 | npm run test 42 | ``` 43 | 44 | 4. Push your branch up to your fork: 45 | ```bash 46 | # Push a feature branch 47 | git push origin feature/thing 48 | ``` 49 | ```bash 50 | # Push a fix branch 51 | git push origin fix/something 52 | ``` 53 | 54 | 5. Now [open a pull request] with a clear title and description. 55 | 56 | [already been reported]: issues 57 | [fork this project]: fork 58 | [live example]: http://codepen.io/pen 59 | [open a pull request]: https://help.github.com/articles/using-pull-requests/ 60 | [reduced test case]: https://css-tricks.com/reduced-test-cases/ 61 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # CC0 1.0 Universal License 2 | 3 | Public Domain Dedication 4 | 5 | The person(s) who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. 6 | 7 | You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. 8 | 9 | In no way are the patent or trademark rights of any person affected by CC0, nor are the rights that other persons may have in the work or in how the work is used, such as publicity or privacy rights. 10 | 11 | Unless expressly stated otherwise, the person(s) who associated a work with this deed makes no warranties about the work, and disclaims liability for all uses of the work, to the fullest extent permitted by applicable law. 12 | 13 | When using or citing the work, you should not imply endorsement by the author or the affirmer. 14 | 15 | This is a [human-readable summary of the Legal Code](https://creativecommons.org/publicdomain/zero/1.0/) ([read the full text](https://creativecommons.org/publicdomain/zero/1.0/legalcode)). 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UnMQ [![Build Status][ci-img]][ci] 2 | 3 | 4 | 5 | [UnMQ] removes media queries from CSS while preserving rules that match a hard-coded viewport. This can be useful for outputting desktop CSS for older browsers like Internet Explorer 8. 6 | 7 | ```css 8 | /* before */ 9 | 10 | body { 11 | font-size: 12px; 12 | } 13 | 14 | @media screen and (max-width: 767px) { 15 | body { 16 | font-size: 16px; 17 | } 18 | } 19 | 20 | @media screen and (min-width: 768px) { 21 | body { 22 | color: #444; 23 | } 24 | } 25 | 26 | /* after */ 27 | 28 | body { 29 | font-size: 12px; 30 | } 31 | 32 | body { 33 | color: #444; 34 | } 35 | ``` 36 | 37 | ## Usage 38 | 39 | Add [UnMQ] to your build tool: 40 | 41 | ```bash 42 | npm install postcss-unmq --save-dev 43 | ``` 44 | 45 | #### Node 46 | 47 | ```js 48 | require('postcss-unmq')({ /* options */ }).process(YOUR_CSS); 49 | ``` 50 | 51 | #### PostCSS 52 | 53 | Add [PostCSS] to your build tool: 54 | 55 | ```bash 56 | npm install postcss --save-dev 57 | ``` 58 | 59 | Load [UnMQ] as a PostCSS plugin: 60 | 61 | ```js 62 | postcss([ 63 | require('postcss-unmq')({ /* options */ }) 64 | ]); 65 | ``` 66 | 67 | #### Gulp 68 | 69 | Add [Gulp PostCSS] to your build tool: 70 | 71 | ```bash 72 | npm install gulp-postcss --save-dev 73 | ``` 74 | 75 | Enable [UnMQ] within your Gulpfile: 76 | 77 | ```js 78 | var postcss = require('gulp-postcss'); 79 | 80 | gulp.task('css', function () { 81 | return gulp.src('./css/src/*.css').pipe( 82 | postcss([ 83 | require('postcss-unmq')({ /* options */ }) 84 | ]) 85 | ).pipe( 86 | gulp.dest('./css') 87 | ); 88 | }); 89 | ``` 90 | 91 | #### Grunt 92 | 93 | Add [Grunt PostCSS] to your build tool: 94 | 95 | ```bash 96 | npm install grunt-postcss --save-dev 97 | ``` 98 | 99 | Enable [UnMQ] within your Gruntfile: 100 | 101 | ```js 102 | grunt.loadNpmTasks('grunt-postcss'); 103 | 104 | grunt.initConfig({ 105 | postcss: { 106 | options: { 107 | processors: [ 108 | require('postcss-unmq')({ /* options */ }) 109 | ] 110 | }, 111 | dist: { 112 | src: 'css/*.css' 113 | } 114 | } 115 | }); 116 | ``` 117 | 118 | ## Options 119 | 120 | You can define your own viewport for media queries to be evaluated against. Think of the options as the current state of a device and browser. 121 | 122 | ```js 123 | require('postcss-unmq')({ 124 | // these are already the default options 125 | type: 'screen', 126 | width: 1024, 127 | height: 768, 128 | resolution: '1dppx', 129 | color: 3 130 | }) 131 | ``` 132 | 133 | If it’s not defined, `device-width` will be given the value of `width`, and `device-height` will be given the value of `height`. Similarly, `aspect-ratio` will be given the value of `device-width` divided by `device-height`. 134 | 135 | [ci]: https://travis-ci.org/jonathantneal/postcss-unmq 136 | [ci-img]: https://travis-ci.org/jonathantneal/postcss-unmq.svg 137 | [Gulp PostCSS]: https://github.com/postcss/gulp-postcss 138 | [Grunt PostCSS]: https://github.com/nDmitry/grunt-postcss 139 | [PostCSS]: https://github.com/postcss/postcss 140 | [UnMQ]: https://github.com/jonathantneal/postcss-unmq 141 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var extend = require('util')._extend; 2 | var postcss = require('postcss'); 3 | var mediaQuery = require('css-mediaquery'); 4 | 5 | var defaultOpts = { 6 | type: 'screen', 7 | width: 1024, 8 | height: 768, 9 | resolution: '1dppx', 10 | color: 3 11 | }; 12 | 13 | module.exports = postcss.plugin('postcss-unmq', function (opts) { 14 | opts = extend(extend({}, defaultOpts), opts); 15 | 16 | if (!('device-width' in opts)) { 17 | opts['device-width'] = opts.width; 18 | } 19 | 20 | if (!('device-height' in opts)) { 21 | opts['device-height'] = opts.height; 22 | } 23 | 24 | if (!('aspect-ratio' in opts)) { 25 | opts['aspect-ratio'] = opts['device-width'] / opts['device-height']; 26 | } 27 | 28 | if (!('orientation' in opts)) { 29 | opts.orientation = opts['aspect-ratio'] >= 1 ? 'landscape' : 'portrait'; 30 | } 31 | 32 | return function (css) { 33 | css.walkAtRules('media', function (rule) { 34 | if (mediaQuery.match(rule.params, opts)) { 35 | rule.replaceWith(rule.nodes); 36 | } else { 37 | rule.remove(); 38 | } 39 | }); 40 | }; 41 | }); 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "postcss-unmq", 3 | "version": "1.0.2", 4 | "description": "Remove media queries from CSS while preserving rules that match a hard-coded viewport", 5 | "keywords": [ 6 | "postcss", 7 | "css", 8 | "postcss-plugin", 9 | "mediaquery", 10 | "mediaqueries", 11 | "internet", 12 | "explorer", 13 | "ie", 14 | "mq", 15 | "strip" 16 | ], 17 | "author": "Jonathan Neal ", 18 | "license": "CC0-1.0", 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/jonathantneal/postcss-unmq.git" 22 | }, 23 | "bugs": { 24 | "url": "https://github.com/jonathantneal/postcss-unmq/issues" 25 | }, 26 | "homepage": "https://github.com/jonathantneal/postcss-unmq", 27 | "dependencies": { 28 | "css-mediaquery": "^0.1.2", 29 | "postcss": "^5.0.10" 30 | }, 31 | "devDependencies": { 32 | "eslint": "^1.7.3", 33 | "tap-spec": "^4.1.0", 34 | "tape": "^4.2.2" 35 | }, 36 | "scripts": { 37 | "lint": "eslint . --ignore-path .gitignore", 38 | "test-fixtures": "tape test/*.js | tap-spec", 39 | "test": "npm run lint && npm run test-fixtures" 40 | }, 41 | "engines": { 42 | "iojs": ">=2.0.0", 43 | "node": ">=0.12.0" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /test/fixtures/aspect-ratio.css: -------------------------------------------------------------------------------- 1 | @media screen and (max-aspect-ratio: 2/1) { 2 | body { 3 | background: black; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/aspect-ratio.expect.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: black 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/basic.css: -------------------------------------------------------------------------------- 1 | @media screen and (min-width: 30em) { 2 | a { 3 | min-width: 30em; 4 | } 5 | } 6 | 7 | @media screen and (min-width: 60em) { 8 | a { 9 | min-width: 60em; 10 | } 11 | } 12 | 13 | @media screen and (max-width: 30em) { 14 | a { 15 | max-width: 30em; 16 | } 17 | } 18 | 19 | @media screen and (max-width: 60em) { 20 | a { 21 | max-width: 60em; 22 | } 23 | } 24 | 25 | @media screen and (min-aspect-ratio: 1) { 26 | a { 27 | line-height: 2; 28 | } 29 | } 30 | 31 | @media screen and (max-aspect-ratio: 1) { 32 | a { 33 | line-height: .5; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/fixtures/basic.expect.css: -------------------------------------------------------------------------------- 1 | a { 2 | 3 | min-width: 30em 4 | } 5 | 6 | a { 7 | 8 | min-width: 60em 9 | } 10 | 11 | a { 12 | 13 | line-height: 2 14 | } 15 | -------------------------------------------------------------------------------- /test/fixtures/basic.width.expect.css: -------------------------------------------------------------------------------- 1 | a { 2 | 3 | max-width: 30em 4 | } 5 | 6 | a { 7 | 8 | max-width: 60em 9 | } 10 | 11 | a { 12 | 13 | line-height: .5 14 | } 15 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | var tests = { 2 | 'postcss-unmq': { 3 | 'basic': { 4 | message: 'supports basic usage' 5 | }, 6 | 'basic:width': { 7 | message: 'supports "width: 320" option', 8 | options: { 9 | width: 320 10 | } 11 | }, 12 | 'aspect-ratio': { 13 | message: 'supports aspect-ratio usage' 14 | } 15 | } 16 | }; 17 | 18 | var debug = true; 19 | var dir = './test/fixtures/'; 20 | 21 | var fs = require('fs'); 22 | var path = require('path'); 23 | var plugin = require('../'); 24 | var test = require('tape'); 25 | 26 | Object.keys(tests).forEach(function (name) { 27 | var parts = tests[name]; 28 | 29 | test(name, function (t) { 30 | var fixtures = Object.keys(parts); 31 | 32 | t.plan(fixtures.length * 2); 33 | 34 | fixtures.forEach(function (fixture) { 35 | var message = parts[fixture].message; 36 | var options = parts[fixture].options; 37 | var warning = parts[fixture].warning || 0; 38 | var warningMsg = message + ' (# of warnings)'; 39 | 40 | var baseName = fixture.split(':')[0]; 41 | var testName = fixture.split(':').join('.'); 42 | 43 | var inputPath = path.resolve(dir + baseName + '.css'); 44 | var expectPath = path.resolve(dir + testName + '.expect.css'); 45 | var actualPath = path.resolve(dir + testName + '.actual.css'); 46 | 47 | var inputCSS = ''; 48 | var expectCSS = ''; 49 | 50 | try { 51 | inputCSS = fs.readFileSync(inputPath, 'utf8'); 52 | } catch (error) { 53 | fs.writeFileSync(inputPath, inputCSS); 54 | } 55 | 56 | try { 57 | expectCSS = fs.readFileSync(expectPath, 'utf8'); 58 | } catch (error) { 59 | fs.writeFileSync(expectPath, expectCSS); 60 | } 61 | 62 | plugin.process(inputCSS, options).then(function (result) { 63 | var actualCSS = result.css; 64 | 65 | if (debug) fs.writeFileSync(actualPath, actualCSS); 66 | 67 | t.equal(actualCSS, expectCSS, message); 68 | 69 | t.equal(result.warnings().length, warning, warningMsg); 70 | }); 71 | }); 72 | }); 73 | }); 74 | --------------------------------------------------------------------------------