├── .eslintrc.js ├── .gitattributes ├── .github └── workflows │ └── linting-and-unit-testing.yml ├── .gitignore ├── CHANGELOG.md ├── ISSUE_TEMPLATE.md ├── LICENSE ├── README.md ├── appveyor.yml ├── bin └── sakugawa.js ├── index.js ├── logo.png ├── npm-shrinkwrap.json ├── package.json ├── renovate.json ├── tests ├── cli_test.js ├── expected │ ├── max-selectors-lower_1.css │ ├── pure_1.css │ └── pure_2.css ├── fixtures │ ├── charset.css │ ├── imports.css │ ├── pure.css │ └── twenty.css └── index_test.js └── wercker.yml /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['paazmaya'], 3 | parserOptions: { 4 | ecmaVersion: 'latest' 5 | }, 6 | rules: { 7 | 'no-console': 0, 8 | 'no-process-exit': 0 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.css eol=lf -------------------------------------------------------------------------------- /.github/workflows/linting-and-unit-testing.yml: -------------------------------------------------------------------------------- 1 | name: Node.js v14 CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Use Node.js v14 13 | uses: actions/setup-node@v2 14 | with: 15 | node-version: '14.x' 16 | - run: npm ci 17 | - run: npm run lint 18 | - run: npm test 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage* 15 | .nyc_output 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # Compiled binary addons (http://nodejs.org/api/addons.html) 21 | build/Release 22 | 23 | # Dependency directory 24 | # Commenting this out is preferred by some people, see 25 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 26 | node_modules 27 | 28 | # Users Environment Variables 29 | .lock-wscript 30 | flow 31 | 32 | *.cpuprofile 33 | *.heapsnapshot 34 | memwatch.* 35 | 36 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Version history for Sakugawa (佐久川) 2 | 3 | This changelog covers the version history and possible upcoming changes. 4 | It follows the guidance from https://keepachangelog.com/en/1.0.0/. 5 | 6 | ## Unreleased 7 | - Minimum supported Node.js version lifted from `10.13.0` to `14.15.0` 8 | 9 | ## `v0.7.0` (2021-02-16) 10 | - Minimum Node.js version lifted from `8.11.1` to `10.13.0` 11 | - Run tests also against Node.js version 14. Now versions 10 (Wercker), 12 (AppVeyor), and 14 (GitHub Actions) of Node.js are covered 12 | - Suffix option did not accept strings because it was configured as `number` #40. Fixed by @gluecksmensch #41 13 | 14 | ## `v0.6.0` (2019-01-26) 15 | - Minimum Node.js version lifted from `4.2.0` to `8.11.1` 16 | - Use [`npm-shrinkwrap.json`](https://docs.npmjs.com/files/shrinkwrap.json) for locking the working set of 3rd party dependencies 17 | 18 | ## `v0.5.3` (2016-08-08) 19 | - Start testing with Windows at AppVeyor 20 | - Move code coverage from `instanbul` to `nyc` 21 | - Document the default value for `--media-queries` command line option 22 | 23 | ## `v0.5.2` (2016-07-10) 24 | - ~~Use `Object.assign()` for cloning AST object, #26~~, did not work as assumed 25 | 26 | ## `v0.5.1` (2015-12-04) 27 | - Code coverage report at codecov #24 28 | - ES2015 variable usage. Was going to use destructuring, but it's not released yet in Node.js 29 | 30 | ## `v0.5.0` (2015-11-16) 31 | - Limit the number of `@import` rules, #2 32 | - Version outputs only `0.5.0` 33 | - Require minimum of Node.js LTS version `4.2.0` 34 | 35 | ## `v0.4.1` (2015-03-11) 36 | - One `var` too many in the previous release 37 | 38 | ## `v0.4.0` (2015-03-11) 39 | - Preserve `@charset` rules, #5 40 | 41 | ## `v0.3.2` (2015-02-25) 42 | - Minimum number of CSS sheets was not followed 43 | - Code coverage with unit tests at 100%, #1 and #8 44 | 45 | ## `v0.3.1` (2015-02-23) 46 | - Use latest `css` version, namely `2.2.0`, which was release five days ago 47 | 48 | ## `v0.3.0` (2015-02-23) 49 | - Possibility to specify minimum amount of generated CSS, #7 50 | 51 | ## `v0.2.1` (2014-12-05) 52 | - Better documentation and command line bin path configured so now usable via global install 53 | 54 | ## `v0.2.0` (2014-11-19) 55 | - Speed improvements 56 | 57 | ## `v0.1.0` (2014-11-17) 58 | - Initial release with splitting against selector count and media query filtering 59 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Expected behaviour 2 | 3 | What it should have accomplished. 4 | 5 | ### Actual behaviour 6 | 7 | How to reproduce with minimal working example. 8 | 9 | ### Versions and environment 10 | 11 | * Operating system: 12 | * Node.js: 13 | * npm: 14 | * sakugawa: 15 | 16 | Thank you and have some :tomato:. 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Juga Paazmaya 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sakugawa (佐久川) 2 | 3 | > CSS splitter, filter and organiser for IE9 and before 4 | 5 | ![Mr Sakugawa](logo.png) 6 | 7 | [![wercker status](https://app.wercker.com/status/d1673adc6fdf3e5c3e4234986517ebc3/s/master "wercker status")](https://app.wercker.com/project/byKey/d1673adc6fdf3e5c3e4234986517ebc3) 8 | [![Windows build status](https://ci.appveyor.com/api/projects/status/67kt1qypoltk3dqf/branch/master?svg=true)](https://ci.appveyor.com/project/paazmaya/sakugawa/branch/master) 9 | [![Node.js v14 CI](https://github.com/paazmaya/sakugawa/actions/workflows/linting-and-unit-testing.yml/badge.svg)](https://github.com/paazmaya/sakugawa/actions/workflows/linting-and-unit-testing.yml) 10 | [![codecov.io](https://codecov.io/github/paazmaya/sakugawa/coverage.svg?branch=master)](https://codecov.io/github/paazmaya/sakugawa?branch=master) 11 | 12 | [Internet Explorer versions from 6 up to 9 come with a limitation][ieinternals] for 13 | selectors present in a single CSS file. This limitation of 4095 selectors created the 14 | need for CSS splitter, which might be the main use case of this task runner plugin. 15 | 16 | Those versions also come with other number related limits, such as the amount of 17 | `@import` rules used in a single file. That limit is 31 for sheets and the imported 18 | sheet can have descending imports up to 4 levels total. 19 | 20 | Since IE8 and earlier, do not support media queries, but IE9 does, there is an option for handling 21 | media queries differently, based on the targeted IE version. By separating media queries in 22 | to a different file, it will allow the to include that CSS file [conditionally][] only when 23 | IE9 is being used. Ideally this would reduce the amount of bytes downloaded by IE8, which 24 | cannot handle the media queries anyhow, and thus prevent downloading something that is not 25 | even used. 26 | 27 | ## Background for the name 28 | 29 | [Mr Sakugawa (佐久川 寛賀, first name Kanga)](http://en.wikipedia.org/wiki/Sakugawa_Kanga) 30 | was a martial artist living in Okinawa, Japan. 31 | He was very important figure in the evolution of the Ryukyu martial arts known today as 32 | Karate and Ryukyu Kobujutsu. In the latter, there are forms named after him, 33 | in which a long six feet wooden staff is used. 34 | 35 | The three forms are called `Sakugawa no kon sho`, `Sakugawa no kon chu`, and `Sakugawa no kon dai`. 36 | [Here is a Youtube video of one of those forms.](https://www.youtube.com/watch?v=KF4nERzknmI) 37 | 38 | ## Installation 39 | 40 | Install globally, in order to use the command line tool. 41 | Might need to use `sudo`, depending of your setup: 42 | 43 | ```sh 44 | npm install --global sakugawa 45 | ``` 46 | 47 | For local installation, in which you could use `--save` or `--save-dev`: 48 | 49 | ```sh 50 | npm install sakugawa 51 | ``` 52 | 53 | Please note that the minimum supported version of [Node.js](https://nodejs.org/en/) is `14.15.0`, which is [the active Long Term Support (LTS) version](https://github.com/nodejs/Release#release-schedule). 54 | 55 | ## Command line usage 56 | 57 | ```sh 58 | Usage: sakugawa [options] huge-stylesheet.css [more CSS files] 59 | 60 | Options: 61 | 62 | -h, --help Show help 63 | -V, --version Show version information 64 | -n, --max-selectors Maximum number of CSS selectors per output file 65 | -i, --max-imports Maximum number of @import rules per output file 66 | -s, --suffix Output CSS file suffix 67 | -M, --minimum-files Minimum number of output CSS files 68 | -m, --media-queries Media query handling, separation to different file (separate) or ignorance (ignore). By default included (normal) 69 | ``` 70 | 71 | Example with [Pure CSS](http://purecss.io/ "A set of small, responsive CSS modules that you can use in every web project"): 72 | 73 | ```sh 74 | sakugawa -n 400 -m separate pure-min.css 75 | ``` 76 | 77 | Would result in creating files `pure-min_1.css` and `pure-min_2.css` in which the latter contains all media queries. 78 | 79 | Please note that the resulting files are not minified. 80 | 81 | The CSS file used in the example can be retrieved with: 82 | 83 | ```sh 84 | wget http://yui.yahooapis.com/pure/0.5.0/pure-min.css 85 | ``` 86 | 87 | 88 | ## Use as a npm module 89 | 90 | First [require][] the `sakugawa` module, which exports itself as a function. 91 | 92 | ```js 93 | var sakugawa = require('sakugawa'); 94 | ``` 95 | 96 | Later on in the script use the `sakugawa` function: 97 | 98 | ```js 99 | var styles = fs.readFileSync('pure.css', 'utf8'); 100 | 101 | var options = { 102 | maxSelectors: 400, 103 | mediaQueries: 'separate' 104 | }; 105 | 106 | var separated = sakugawa(styles, options); 107 | // Separated is an array of CSS strings 108 | 109 | separated.forEach(function eachPages(css, index) { 110 | fs.writeFileSync('pure_' + (index + 1) + '.css', css, 'utf8'); 111 | }); 112 | ``` 113 | 114 | Available options are shown below and assigned to their default values: 115 | 116 | ```js 117 | var options = { 118 | maxSelectors: 4090, 119 | mediaQueries: 'normal', 120 | filename: 'input.css', // Not used at the moment for anything 121 | minSheets: 1 122 | }; 123 | ``` 124 | 125 | The above used options map to the same as used via command line and thus have the same 126 | defaults and allowed values. Please note however, that the `minSheets` is used as 127 | `--minimum-files` via command line, since the command line version is touching files, 128 | while the API provided is only touching strings. 129 | 130 | 131 | ## Task runners 132 | 133 | * [gulp-sakugawa](https://github.com/paazmaya/gulp-sakugawa "Run Sakugawa via gulp, for CSS splitting, filtering and organising") 134 | * [grunt-sakugawa](https://github.com/paazmaya/grunt-sakugawa "Run Sakugawa via Grunt, for CSS splitting, filtering and organising") 135 | 136 | ## Contributing 137 | 138 | ["A Beginner's Guide to Open Source: The Best Advice for Making your First Contribution"](http://www.erikaheidi.com/blog/a-beginners-guide-to-open-source-the-best-advice-for-making-your-first-contribution/). 139 | 140 | [Also there is a blog post about "45 Github Issues Dos and Don’ts"](https://davidwalsh.name/45-github-issues-dos-donts). 141 | 142 | Linting is done with [ESLint](http://eslint.org) and can be executed with `npm run lint`. 143 | There should be no errors appearing after any JavaScript file changes. 144 | 145 | Unit tests are written with [`tape`](https://github.com/substack/tape) and can be executed with `npm test`. 146 | Code coverage is inspected with [`nyc`](https://github.com/istanbuljs/nyc) and 147 | can be executed with `npm run coverage` after running `npm test`. 148 | Please make sure it is over 90% at all times. 149 | 150 | ## Version history 151 | 152 | [Changes happening across different versions and upcoming changes are tracked in the `CHANGELOG.md` file.](CHANGELOG.md) 153 | 154 | ## License 155 | 156 | Copyright (c) [Juga Paazmaya](https://paazmaya.fi) 157 | 158 | Licensed under the [MIT license](LICENSE). 159 | 160 | 161 | [ieinternals]: http://blogs.msdn.com/b/ieinternals/archive/2011/05/14/10164546.aspx "Stylesheet Limits in Internet Explorer" 162 | [conditionally]: http://www.quirksmode.org/css/condcom.html "Conditional comments" 163 | [require]: http://nodejs.org/api/modules.html#modules_module_require_id "The module.require method provides a way to load a module as if require() was called from the original module" 164 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # http://www.appveyor.com/docs/appveyor-yml 2 | 3 | environment: 4 | matrix: 5 | - nodejs_version: "16" 6 | 7 | version: "{build}-{branch}" 8 | 9 | init: 10 | - git config --global core.longpaths true 11 | 12 | clone_depth: 1 13 | 14 | matrix: 15 | fast_finish: true 16 | 17 | cache: 18 | - node_modules 19 | 20 | install: 21 | - ps: Install-Product node $env:nodejs_version 22 | - npm install 23 | 24 | test_script: 25 | - node --version 26 | - npm --version 27 | - npm run lint 28 | - npm test 29 | 30 | build: off 31 | -------------------------------------------------------------------------------- /bin/sakugawa.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* @flow */ 3 | /** 4 | * Sakugawa 5 | * https://github.com/paazmaya/sakugawa 6 | * 7 | * Copyright (c) Juga Paazmaya (https://paazmaya.fi) 8 | * Licensed under the MIT license. 9 | */ 10 | 11 | 12 | // Usually first variables defined are the ones requiring native Node.js modules 13 | const fs = require('fs'), 14 | path = require('path'); 15 | 16 | // It might be good for organisation, to have another variable set for local modules 17 | const Bossy = require('bossy'); 18 | 19 | // Local files 20 | const sakugawa = require('../index'); 21 | 22 | // Default command line options 23 | const cmdOptions = { 24 | h: { 25 | description: 'Show help', 26 | alias: 'help', 27 | type: 'boolean' 28 | }, 29 | V: { 30 | description: 'Show version information', 31 | alias: 'version', 32 | type: 'boolean' 33 | }, 34 | n: { 35 | description: 'Maximum number of CSS selectors per output file', 36 | alias: 'max-selectors', 37 | type: 'number', 38 | default: 4090 39 | }, 40 | i: { 41 | description: 'Maximum number of @import rules per output file', 42 | alias: 'max-imports', 43 | type: 'number', 44 | default: 4 45 | }, 46 | s: { 47 | description: 'Output CSS file suffix', 48 | alias: 'suffix', 49 | type: 'string', 50 | default: '_' 51 | }, 52 | M: { 53 | description: 'Minimum number of output CSS files', 54 | alias: 'minimum-files', 55 | type: 'number', 56 | default: 1 57 | }, 58 | m: { 59 | description: 'Media query handling, separation to different file (separate) or ignorance (ignore). By default included (normal)', 60 | alias: 'media-queries', 61 | type: 'string', 62 | valid: ['separate', 'ignore', 'normal'] 63 | } 64 | }; 65 | 66 | // Initialise and parse command line arguments against the default options 67 | const args = Bossy.parse(cmdOptions); 68 | 69 | // In case parsing failed, stop execution with an error 70 | if (args instanceof Error) { 71 | console.error(args.message); 72 | 73 | return; 74 | } 75 | 76 | if (args.V) { 77 | const json = fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'); 78 | try { 79 | const pkg = JSON.parse(json); 80 | console.log(pkg.version); 81 | } 82 | catch (error) { 83 | console.error('Could not parse "package.json", very strange...'); 84 | } 85 | 86 | return; 87 | } 88 | 89 | // In case help or version information is specifically requested, only that should be outputted 90 | if (args.h || !args._) { 91 | console.log(Bossy.usage(cmdOptions, 'sakugawa [options] huge-stylesheet.css [more CSS files]')); 92 | 93 | return; 94 | } 95 | 96 | // files, an array or string 97 | if (args._) { 98 | let files = args._; 99 | if (typeof files === 'string') { 100 | files = [files]; 101 | } 102 | files = files.filter((file) => { 103 | return fs.existsSync(file); 104 | }); 105 | 106 | const opts = { 107 | maxSelectors: args.n, 108 | minSheets: args.M, 109 | mediaQueries: args.m 110 | }; 111 | 112 | files.forEach((file) => { 113 | console.log('Reading ' + file); 114 | const styles = fs.readFileSync(file, 'utf8'); 115 | const pages = sakugawa(styles, opts); 116 | pages.forEach(function eachPages(page, index) { 117 | // page is a CSS string 118 | const pageFile = file.replace(/\.css$/u, args.s + (index + 1) + '.css'); 119 | console.log('Writing ' + pageFile); 120 | fs.writeFileSync(pageFile, page, 'utf8'); 121 | }); 122 | }); 123 | } 124 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sakugawa 3 | * https://github.com/paazmaya/sakugawa 4 | * 5 | * Copyright (c) Juga Paazmaya (https://paazmaya.fi) 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | 10 | const css = require('css'); 11 | // const postcss = require('postcss'); 12 | 13 | class Sakugawa { 14 | constructor (styles, options) { 15 | if (typeof styles !== 'string') { 16 | throw new Error('styles must be a string'); 17 | } 18 | 19 | if (styles.length < 1) { 20 | throw new Error('styles must not be empty'); 21 | } 22 | 23 | options = options || {}; 24 | this.maxSelectors = options.maxSelectors || 4090; 25 | this.maxImports = options.maxImports || 4; 26 | this.mediaQueries = options.mediaQueries || 'normal'; 27 | this.filename = options.filename || 'input.css'; 28 | this.minSheets = options.minSheets || 1; 29 | 30 | this.ast = css.parse(styles); 31 | } 32 | 33 | _clone(ast) { 34 | 35 | // Store temporarily elsewhere to speed up cloning 36 | const origRules = ast.stylesheet.rules; 37 | ast.stylesheet.rules = []; 38 | 39 | const clone = JSON.parse(JSON.stringify(ast)); 40 | ast.stylesheet.rules = origRules; 41 | 42 | clone.stylesheet.rules = []; 43 | 44 | // Handle charset copying, if such exists 45 | const charsetRules = origRules.filter((rule) => { 46 | return rule.type === 'charset'; 47 | }); 48 | if (charsetRules.length > 0) { 49 | clone.stylesheet.rules = charsetRules; 50 | } 51 | 52 | return clone; 53 | } 54 | 55 | _countSelectors(rule, includeMedia) { 56 | let total = 0; 57 | 58 | if (rule.type === 'rule' && typeof rule.selectors === 'object') { 59 | total += rule.selectors.length; 60 | } 61 | else if (includeMedia && rule.type === 'media' && rule.rules) { 62 | rule.rules.forEach((media) => { 63 | total += this._countSelectors(media, true); // even while media should not contain media... 64 | }); 65 | } 66 | 67 | return total; 68 | } 69 | 70 | _generatePages(rules, ast) { 71 | const pages = []; 72 | 73 | let clone, 74 | selectorsForThisPage = 0; 75 | 76 | // Remove charset rules since they are added when clone is created 77 | rules = rules.filter(function filterNonCharsetRules(rule) { 78 | return rule.type !== 'charset'; 79 | }); 80 | 81 | rules.forEach((rule) => { 82 | const selectorCount = this._countSelectors(rule, true); 83 | 84 | if (clone && selectorsForThisPage + selectorCount <= this.maxSelectors) { 85 | selectorsForThisPage += selectorCount; 86 | clone.stylesheet.rules.push(rule); 87 | } 88 | else { 89 | // Restart 90 | selectorsForThisPage = selectorCount; 91 | clone = this._clone(ast); 92 | clone.stylesheet.rules.push(rule); 93 | pages.push(clone); 94 | } 95 | }); 96 | 97 | return pages; 98 | } 99 | 100 | createPages() { 101 | let pages = [], 102 | { 103 | rules 104 | } = this.ast.stylesheet; 105 | 106 | // Remove media queries from the first iteration when not needed there 107 | if (this.mediaQueries !== 'normal') { 108 | rules = rules.filter((rule) => { 109 | return rule.type !== 'media'; 110 | }); 111 | } 112 | 113 | pages = this._generatePages(rules, this.ast); 114 | 115 | // Separate media queries 116 | if (this.mediaQueries === 'separate') { 117 | const mediaRules = this.ast.stylesheet.rules.filter((rule) => { 118 | return rule.type === 'media'; 119 | }); 120 | 121 | pages = pages.concat(this._generatePages(mediaRules, this.ast)); 122 | } 123 | 124 | return pages; 125 | } 126 | 127 | getPages() { 128 | const pages = this.createPages(); 129 | const sheets = pages.map((page) => { 130 | const str = css.stringify(page); 131 | 132 | return str; 133 | }); 134 | while (sheets.length < this.minSheets) { 135 | sheets.push(''); 136 | } 137 | 138 | return sheets; 139 | } 140 | } 141 | 142 | module.exports = function exports(styles, options) { 143 | const s = new Sakugawa(styles, options); 144 | 145 | return s.getPages(); 146 | }; 147 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paazmaya/sakugawa/79f5e52b3934828b1d1416dce7422f2018b2831f/logo.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sakugawa", 3 | "version": "0.7.0", 4 | "description": "CSS splitter, filter and organiser for IE9 and before", 5 | "homepage": "https://github.com/paazmaya/sakugawa", 6 | "author": { 7 | "name": "Juga Paazmaya", 8 | "email": "paazmaya@yahoo.com", 9 | "url": "https://paazmaya.fi" 10 | }, 11 | "main": "index.js", 12 | "bin": "bin/sakugawa.js", 13 | "scripts": { 14 | "lint": "eslint bin/sakugawa.js index.js", 15 | "test": "nyc --all --exclude tests tape tests/*_test.js", 16 | "coverage": "nyc --all --exclude tests report --reporter=text-lcov > coverage.lcov && codecov" 17 | }, 18 | "files": [ 19 | "bin", 20 | "index.js", 21 | "npm-shrinkwrap.json", 22 | "README.md", 23 | "LICENSE" 24 | ], 25 | "repository": { 26 | "type": "git", 27 | "url": "git://github.com/paazmaya/sakugawa.git" 28 | }, 29 | "keywords": [ 30 | "css", 31 | "selector", 32 | "ie8", 33 | "ie9", 34 | "media-query", 35 | "import", 36 | "split", 37 | "filter", 38 | "organize" 39 | ], 40 | "license": "MIT", 41 | "bugs": { 42 | "url": "https://github.com/paazmaya/sakugawa/issues" 43 | }, 44 | "engines": { 45 | "node": ">=14.15.0" 46 | }, 47 | "dependencies": { 48 | "bossy": "~4.0", 49 | "css": "~3.0" 50 | }, 51 | "devDependencies": { 52 | "codecov": "3.8.3", 53 | "eslint": "7.32.0", 54 | "eslint-config-paazmaya": "7.2.0", 55 | "nyc": "15.1.0", 56 | "tape": "5.5.3" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "commitBody": "Signed-off-by: {{{gitAuthor}}}", 6 | "automerge": true, 7 | "labels": [ 8 | "dependencies" 9 | ], 10 | "major": { 11 | "automerge": false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/cli_test.js: -------------------------------------------------------------------------------- 1 | /* @flow weak */ 2 | /** 3 | * Sakugawa 4 | * https://github.com/paazmaya/sakugawa 5 | * 6 | * Copyright (c) Juga Paazmaya (https://paazmaya.fi) 7 | * Licensed under the MIT license. 8 | */ 9 | 10 | 11 | const fs = require('fs'), 12 | path = require('path'), 13 | { 14 | execFile 15 | } = require('child_process'); 16 | 17 | const tape = require('tape'); 18 | 19 | const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8')); 20 | 21 | tape('cli should output version number', (test) => { 22 | test.plan(1); 23 | 24 | execFile('node', [pkg.bin, '-V'], null, (err, stdout) => { 25 | test.equals(stdout.trim(), pkg.version, 'Version is the same as in package.json'); 26 | }); 27 | 28 | }); 29 | 30 | tape('cli should output help by default', (test) => { 31 | test.plan(1); 32 | 33 | execFile('node', [pkg.bin], null, (err, stdout) => { 34 | test.ok(stdout.trim().indexOf('sakugawa [options] huge-stylesheet.css [more CSS files]') !== -1, 'Help appeared'); 35 | }); 36 | 37 | }); 38 | 39 | tape('cli should output help when requested', (test) => { 40 | test.plan(1); 41 | 42 | execFile('node', [pkg.bin, '--help'], null, (err, stdout) => { 43 | test.ok(stdout.trim().indexOf('sakugawa [options] huge-stylesheet.css [more CSS files]') !== -1, 'Help appeared'); 44 | }); 45 | 46 | }); 47 | 48 | -------------------------------------------------------------------------------- /tests/expected/max-selectors-lower_1.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v0.5.0, reduced to twenty selectors, with media queries 3 | Copyright 2014 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | https://github.com/yui/pure/blob/master/LICENSE.md 6 | */ 7 | 8 | .pure-img { 9 | max-width: 100%; 10 | height: auto; 11 | display: block; 12 | } 13 | 14 | .pure-button { 15 | -ms-user-select: none; 16 | user-select: none; 17 | } 18 | 19 | .pure-button { 20 | border-radius: 2px; 21 | } 22 | 23 | .pure-button:focus { 24 | outline: 0; 25 | } 26 | 27 | .pure-button-active, 28 | .pure-button:active { 29 | box-shadow: 0 0 0 1px rgba(0, 0, 0, .15) inset, 0 0 6px rgba(0, 0, 0, .2) inset; 30 | } 31 | 32 | .pure-button-primary, 33 | .pure-button-selected, 34 | a.pure-button-primary, 35 | a.pure-button-selected { 36 | background-color: #0078e7; 37 | color: #fff; 38 | } 39 | 40 | .pure-menu, 41 | .pure-menu-heading { 42 | color: #565d64; 43 | text-transform: uppercase; 44 | font-size: 90%; 45 | margin-top: .5em; 46 | border-bottom-width: 1px; 47 | border-bottom-style: solid; 48 | border-bottom-color: #dfdfdf; 49 | } 50 | 51 | .pure-menu, 52 | .pure-menu-selected a { 53 | color: #000; 54 | } 55 | 56 | .pure-menu.pure-menu-open, 57 | .pure-menu-fixed { 58 | border: 0; 59 | border-bottom: 1px solid #b7b7b7; 60 | } -------------------------------------------------------------------------------- /tests/expected/pure_1.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v0.5.0 3 | Copyright 2014 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | https://github.com/yui/pure/blob/master/LICENSE.md 6 | */ 7 | 8 | /*! 9 | normalize.css v1.1.3 | MIT License | git.io/normalize 10 | Copyright (c) Nicolas Gallagher and Jonathan Neal 11 | */ 12 | 13 | /*! normalize.css v1.1.3 | MIT License | git.io/normalize */ 14 | 15 | article, 16 | aside, 17 | details, 18 | figcaption, 19 | figure, 20 | footer, 21 | header, 22 | hgroup, 23 | main, 24 | nav, 25 | section, 26 | summary { 27 | display: block; 28 | } 29 | 30 | audio, 31 | canvas, 32 | video { 33 | display: inline-block; 34 | *display: inline; 35 | *zoom: 1; 36 | } 37 | 38 | audio:not([controls]) { 39 | display: none; 40 | height: 0; 41 | } 42 | 43 | [hidden] { 44 | display: none; 45 | } 46 | 47 | html { 48 | font-size: 100%; 49 | -ms-text-size-adjust: 100%; 50 | -webkit-text-size-adjust: 100%; 51 | } 52 | 53 | html, 54 | button, 55 | input, 56 | select, 57 | textarea { 58 | font-family: sans-serif; 59 | } 60 | 61 | body { 62 | margin: 0; 63 | } 64 | 65 | a:focus { 66 | outline: thin dotted; 67 | } 68 | 69 | a:active, 70 | a:hover { 71 | outline: 0; 72 | } 73 | 74 | h1 { 75 | font-size: 2em; 76 | margin: .67em 0; 77 | } 78 | 79 | h2 { 80 | font-size: 1.5em; 81 | margin: .83em 0; 82 | } 83 | 84 | h3 { 85 | font-size: 1.17em; 86 | margin: 1em 0; 87 | } 88 | 89 | h4 { 90 | font-size: 1em; 91 | margin: 1.33em 0; 92 | } 93 | 94 | h5 { 95 | font-size: .83em; 96 | margin: 1.67em 0; 97 | } 98 | 99 | h6 { 100 | font-size: .67em; 101 | margin: 2.33em 0; 102 | } 103 | 104 | abbr[title] { 105 | border-bottom: 1px dotted; 106 | } 107 | 108 | b, 109 | strong { 110 | font-weight: 700; 111 | } 112 | 113 | blockquote { 114 | margin: 1em 40px; 115 | } 116 | 117 | dfn { 118 | font-style: italic; 119 | } 120 | 121 | hr { 122 | -moz-box-sizing: content-box; 123 | box-sizing: content-box; 124 | height: 0; 125 | } 126 | 127 | mark { 128 | background: #ff0; 129 | color: #000; 130 | } 131 | 132 | p, 133 | pre { 134 | margin: 1em 0; 135 | } 136 | 137 | code, 138 | kbd, 139 | pre, 140 | samp { 141 | font-family: monospace, serif; 142 | _font-family: 'courier new', monospace; 143 | font-size: 1em; 144 | } 145 | 146 | pre { 147 | white-space: pre; 148 | white-space: pre-wrap; 149 | word-wrap: break-word; 150 | } 151 | 152 | q { 153 | quotes: none; 154 | } 155 | 156 | q:before, 157 | q:after { 158 | content: ''; 159 | content: none; 160 | } 161 | 162 | small { 163 | font-size: 80%; 164 | } 165 | 166 | sub, 167 | sup { 168 | font-size: 75%; 169 | line-height: 0; 170 | position: relative; 171 | vertical-align: baseline; 172 | } 173 | 174 | sup { 175 | top: -.5em; 176 | } 177 | 178 | sub { 179 | bottom: -.25em; 180 | } 181 | 182 | dl, 183 | menu, 184 | ol, 185 | ul { 186 | margin: 1em 0; 187 | } 188 | 189 | dd { 190 | margin: 0 0 0 40px; 191 | } 192 | 193 | menu, 194 | ol, 195 | ul { 196 | padding: 0 0 0 40px; 197 | } 198 | 199 | nav ul, 200 | nav ol { 201 | list-style: none; 202 | list-style-image: none; 203 | } 204 | 205 | img { 206 | border: 0; 207 | -ms-interpolation-mode: bicubic; 208 | } 209 | 210 | svg:not(:root) { 211 | overflow: hidden; 212 | } 213 | 214 | figure { 215 | margin: 0; 216 | } 217 | 218 | form { 219 | margin: 0; 220 | } 221 | 222 | fieldset { 223 | border: 1px solid silver; 224 | margin: 0 2px; 225 | padding: .35em .625em .75em; 226 | } 227 | 228 | legend { 229 | border: 0; 230 | padding: 0; 231 | white-space: normal; 232 | *margin-left: -7px; 233 | } 234 | 235 | button, 236 | input, 237 | select, 238 | textarea { 239 | font-size: 100%; 240 | margin: 0; 241 | vertical-align: baseline; 242 | *vertical-align: middle; 243 | } 244 | 245 | button, 246 | input { 247 | line-height: normal; 248 | } 249 | 250 | button, 251 | select { 252 | text-transform: none; 253 | } 254 | 255 | button, 256 | html input[type=button], 257 | input[type=reset], 258 | input[type=submit] { 259 | -webkit-appearance: button; 260 | cursor: pointer; 261 | *overflow: visible; 262 | } 263 | 264 | button[disabled], 265 | html input[disabled] { 266 | cursor: default; 267 | } 268 | 269 | input[type=checkbox], 270 | input[type=radio] { 271 | box-sizing: border-box; 272 | padding: 0; 273 | *height: 13px; 274 | *width: 13px; 275 | } 276 | 277 | input[type=search] { 278 | -webkit-appearance: textfield; 279 | -moz-box-sizing: content-box; 280 | -webkit-box-sizing: content-box; 281 | box-sizing: content-box; 282 | } 283 | 284 | input[type=search]::-webkit-search-cancel-button, 285 | input[type=search]::-webkit-search-decoration { 286 | -webkit-appearance: none; 287 | } 288 | 289 | button::-moz-focus-inner, 290 | input::-moz-focus-inner { 291 | border: 0; 292 | padding: 0; 293 | } 294 | 295 | textarea { 296 | overflow: auto; 297 | vertical-align: top; 298 | } 299 | 300 | table { 301 | border-collapse: collapse; 302 | border-spacing: 0; 303 | } 304 | 305 | [hidden] { 306 | display: none !important; 307 | } 308 | 309 | .pure-img { 310 | max-width: 100%; 311 | height: auto; 312 | display: block; 313 | } 314 | 315 | .pure-g { 316 | letter-spacing: -.31em; 317 | *letter-spacing: normal; 318 | *word-spacing: -.43em; 319 | text-rendering: optimizespeed; 320 | font-family: FreeSans, Arimo, "Droid Sans", Helvetica, Arial, sans-serif; 321 | display: -webkit-flex; 322 | -webkit-flex-flow: row wrap; 323 | display: -ms-flexbox; 324 | -ms-flex-flow: row wrap; 325 | } 326 | 327 | .opera-only :-o-prefocus, 328 | .pure-g { 329 | word-spacing: -.43em; 330 | } 331 | 332 | .pure-u { 333 | display: inline-block; 334 | *display: inline; 335 | zoom: 1; 336 | letter-spacing: normal; 337 | word-spacing: normal; 338 | vertical-align: top; 339 | text-rendering: auto; 340 | } 341 | 342 | .pure-g [class *="pure-u"] { 343 | font-family: sans-serif; 344 | } 345 | 346 | .pure-u-1, 347 | .pure-u-1-1, 348 | .pure-u-1-2, 349 | .pure-u-1-3, 350 | .pure-u-2-3, 351 | .pure-u-1-4, 352 | .pure-u-3-4, 353 | .pure-u-1-5, 354 | .pure-u-2-5, 355 | .pure-u-3-5, 356 | .pure-u-4-5, 357 | .pure-u-5-5, 358 | .pure-u-1-6, 359 | .pure-u-5-6, 360 | .pure-u-1-8, 361 | .pure-u-3-8, 362 | .pure-u-5-8, 363 | .pure-u-7-8, 364 | .pure-u-1-12, 365 | .pure-u-5-12, 366 | .pure-u-7-12, 367 | .pure-u-11-12, 368 | .pure-u-1-24, 369 | .pure-u-2-24, 370 | .pure-u-3-24, 371 | .pure-u-4-24, 372 | .pure-u-5-24, 373 | .pure-u-6-24, 374 | .pure-u-7-24, 375 | .pure-u-8-24, 376 | .pure-u-9-24, 377 | .pure-u-10-24, 378 | .pure-u-11-24, 379 | .pure-u-12-24, 380 | .pure-u-13-24, 381 | .pure-u-14-24, 382 | .pure-u-15-24, 383 | .pure-u-16-24, 384 | .pure-u-17-24, 385 | .pure-u-18-24, 386 | .pure-u-19-24, 387 | .pure-u-20-24, 388 | .pure-u-21-24, 389 | .pure-u-22-24, 390 | .pure-u-23-24, 391 | .pure-u-24-24 { 392 | display: inline-block; 393 | *display: inline; 394 | zoom: 1; 395 | letter-spacing: normal; 396 | word-spacing: normal; 397 | vertical-align: top; 398 | text-rendering: auto; 399 | } 400 | 401 | .pure-u-1-24 { 402 | width: 4.1667%; 403 | *width: 4.1357%; 404 | } 405 | 406 | .pure-u-1-12, 407 | .pure-u-2-24 { 408 | width: 8.3333%; 409 | *width: 8.3023%; 410 | } 411 | 412 | .pure-u-1-8, 413 | .pure-u-3-24 { 414 | width: 12.5%; 415 | *width: 12.469%; 416 | } 417 | 418 | .pure-u-1-6, 419 | .pure-u-4-24 { 420 | width: 16.6667%; 421 | *width: 16.6357%; 422 | } 423 | 424 | .pure-u-1-5 { 425 | width: 20%; 426 | *width: 19.969%; 427 | } 428 | 429 | .pure-u-5-24 { 430 | width: 20.8333%; 431 | *width: 20.8023%; 432 | } 433 | 434 | .pure-u-1-4, 435 | .pure-u-6-24 { 436 | width: 25%; 437 | *width: 24.969%; 438 | } 439 | 440 | .pure-u-7-24 { 441 | width: 29.1667%; 442 | *width: 29.1357%; 443 | } 444 | 445 | .pure-u-1-3, 446 | .pure-u-8-24 { 447 | width: 33.3333%; 448 | *width: 33.3023%; 449 | } 450 | 451 | .pure-u-3-8, 452 | .pure-u-9-24 { 453 | width: 37.5%; 454 | *width: 37.469%; 455 | } 456 | 457 | .pure-u-2-5 { 458 | width: 40%; 459 | *width: 39.969%; 460 | } 461 | 462 | .pure-u-5-12, 463 | .pure-u-10-24 { 464 | width: 41.6667%; 465 | *width: 41.6357%; 466 | } 467 | 468 | .pure-u-11-24 { 469 | width: 45.8333%; 470 | *width: 45.8023%; 471 | } 472 | 473 | .pure-u-1-2, 474 | .pure-u-12-24 { 475 | width: 50%; 476 | *width: 49.969%; 477 | } 478 | 479 | .pure-u-13-24 { 480 | width: 54.1667%; 481 | *width: 54.1357%; 482 | } 483 | 484 | .pure-u-7-12, 485 | .pure-u-14-24 { 486 | width: 58.3333%; 487 | *width: 58.3023%; 488 | } 489 | 490 | .pure-u-3-5 { 491 | width: 60%; 492 | *width: 59.969%; 493 | } 494 | 495 | .pure-u-5-8, 496 | .pure-u-15-24 { 497 | width: 62.5%; 498 | *width: 62.469%; 499 | } 500 | 501 | .pure-u-2-3, 502 | .pure-u-16-24 { 503 | width: 66.6667%; 504 | *width: 66.6357%; 505 | } 506 | 507 | .pure-u-17-24 { 508 | width: 70.8333%; 509 | *width: 70.8023%; 510 | } 511 | 512 | .pure-u-3-4, 513 | .pure-u-18-24 { 514 | width: 75%; 515 | *width: 74.969%; 516 | } 517 | 518 | .pure-u-19-24 { 519 | width: 79.1667%; 520 | *width: 79.1357%; 521 | } 522 | 523 | .pure-u-4-5 { 524 | width: 80%; 525 | *width: 79.969%; 526 | } 527 | 528 | .pure-u-5-6, 529 | .pure-u-20-24 { 530 | width: 83.3333%; 531 | *width: 83.3023%; 532 | } 533 | 534 | .pure-u-7-8, 535 | .pure-u-21-24 { 536 | width: 87.5%; 537 | *width: 87.469%; 538 | } 539 | 540 | .pure-u-11-12, 541 | .pure-u-22-24 { 542 | width: 91.6667%; 543 | *width: 91.6357%; 544 | } 545 | 546 | .pure-u-23-24 { 547 | width: 95.8333%; 548 | *width: 95.8023%; 549 | } 550 | 551 | .pure-u-1, 552 | .pure-u-1-1, 553 | .pure-u-5-5, 554 | .pure-u-24-24 { 555 | width: 100%; 556 | } 557 | 558 | .pure-button { 559 | display: inline-block; 560 | *display: inline; 561 | zoom: 1; 562 | line-height: normal; 563 | white-space: nowrap; 564 | vertical-align: baseline; 565 | text-align: center; 566 | cursor: pointer; 567 | -webkit-user-drag: none; 568 | -webkit-user-select: none; 569 | -moz-user-select: none; 570 | -ms-user-select: none; 571 | user-select: none; 572 | } 573 | 574 | .pure-button::-moz-focus-inner { 575 | padding: 0; 576 | border: 0; 577 | } 578 | 579 | .pure-button { 580 | font-family: inherit; 581 | font-size: 100%; 582 | *font-size: 90%; 583 | *overflow: visible; 584 | padding: .5em 1em; 585 | color: #444; 586 | color: rgba(0, 0, 0, .8); 587 | *color: #444; 588 | border: 1px solid #999; 589 | border: 0 rgba(0, 0, 0, 0); 590 | background-color: #E6E6E6; 591 | text-decoration: none; 592 | border-radius: 2px; 593 | } 594 | 595 | .pure-button-hover, 596 | .pure-button:hover, 597 | .pure-button:focus { 598 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000', GradientType=0); 599 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(transparent), color-stop(40%, rgba(0, 0, 0, .05)), to(rgba(0, 0, 0, .1))); 600 | background-image: -webkit-linear-gradient(transparent, rgba(0, 0, 0, .05) 40%, rgba(0, 0, 0, .1)); 601 | background-image: -moz-linear-gradient(top, rgba(0, 0, 0, .05) 0, rgba(0, 0, 0, .1)); 602 | background-image: -o-linear-gradient(transparent, rgba(0, 0, 0, .05) 40%, rgba(0, 0, 0, .1)); 603 | background-image: linear-gradient(transparent, rgba(0, 0, 0, .05) 40%, rgba(0, 0, 0, .1)); 604 | } 605 | 606 | .pure-button:focus { 607 | outline: 0; 608 | } 609 | 610 | .pure-button-active, 611 | .pure-button:active { 612 | box-shadow: 0 0 0 1px rgba(0, 0, 0, .15) inset, 0 0 6px rgba(0, 0, 0, .2) inset; 613 | } 614 | 615 | .pure-button[disabled], 616 | .pure-button-disabled, 617 | .pure-button-disabled:hover, 618 | .pure-button-disabled:focus, 619 | .pure-button-disabled:active { 620 | border: 0; 621 | background-image: none; 622 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 623 | filter: alpha(opacity=40); 624 | -khtml-opacity: .4; 625 | -moz-opacity: .4; 626 | opacity: .4; 627 | cursor: not-allowed; 628 | box-shadow: none; 629 | } 630 | 631 | .pure-button-hidden { 632 | display: none; 633 | } 634 | 635 | .pure-button::-moz-focus-inner { 636 | padding: 0; 637 | border: 0; 638 | } 639 | 640 | .pure-button-primary, 641 | .pure-button-selected, 642 | a.pure-button-primary, 643 | a.pure-button-selected { 644 | background-color: #0078e7; 645 | color: #fff; 646 | } 647 | 648 | .pure-form input[type=text], 649 | .pure-form input[type=password], 650 | .pure-form input[type=email], 651 | .pure-form input[type=url], 652 | .pure-form input[type=date], 653 | .pure-form input[type=month], 654 | .pure-form input[type=time], 655 | .pure-form input[type=datetime], 656 | .pure-form input[type=datetime-local], 657 | .pure-form input[type=week], 658 | .pure-form input[type=number], 659 | .pure-form input[type=search], 660 | .pure-form input[type=tel], 661 | .pure-form input[type=color], 662 | .pure-form select, 663 | .pure-form textarea { 664 | padding: .5em .6em; 665 | display: inline-block; 666 | border: 1px solid #ccc; 667 | box-shadow: inset 0 1px 3px #ddd; 668 | border-radius: 4px; 669 | -webkit-box-sizing: border-box; 670 | -moz-box-sizing: border-box; 671 | box-sizing: border-box; 672 | } 673 | 674 | .pure-form input:not([type]) { 675 | padding: .5em .6em; 676 | display: inline-block; 677 | border: 1px solid #ccc; 678 | box-shadow: inset 0 1px 3px #ddd; 679 | border-radius: 4px; 680 | -webkit-box-sizing: border-box; 681 | -moz-box-sizing: border-box; 682 | box-sizing: border-box; 683 | } 684 | 685 | .pure-form input[type=color] { 686 | padding: .2em .5em; 687 | } 688 | 689 | .pure-form input[type=text]:focus, 690 | .pure-form input[type=password]:focus, 691 | .pure-form input[type=email]:focus, 692 | .pure-form input[type=url]:focus, 693 | .pure-form input[type=date]:focus, 694 | .pure-form input[type=month]:focus, 695 | .pure-form input[type=time]:focus, 696 | .pure-form input[type=datetime]:focus, 697 | .pure-form input[type=datetime-local]:focus, 698 | .pure-form input[type=week]:focus, 699 | .pure-form input[type=number]:focus, 700 | .pure-form input[type=search]:focus, 701 | .pure-form input[type=tel]:focus, 702 | .pure-form input[type=color]:focus, 703 | .pure-form select:focus, 704 | .pure-form textarea:focus { 705 | outline: 0; 706 | outline: thin dotted \9; 707 | border-color: #129FEA; 708 | } 709 | 710 | .pure-form input:not([type]):focus { 711 | outline: 0; 712 | outline: thin dotted \9; 713 | border-color: #129FEA; 714 | } 715 | 716 | .pure-form input[type=file]:focus, 717 | .pure-form input[type=radio]:focus, 718 | .pure-form input[type=checkbox]:focus { 719 | outline: thin dotted #333; 720 | outline: 1px auto #129FEA; 721 | } 722 | 723 | .pure-form .pure-checkbox, 724 | .pure-form .pure-radio { 725 | margin: .5em 0; 726 | display: block; 727 | } 728 | 729 | .pure-form input[type=text][disabled], 730 | .pure-form input[type=password][disabled], 731 | .pure-form input[type=email][disabled], 732 | .pure-form input[type=url][disabled], 733 | .pure-form input[type=date][disabled], 734 | .pure-form input[type=month][disabled], 735 | .pure-form input[type=time][disabled], 736 | .pure-form input[type=datetime][disabled], 737 | .pure-form input[type=datetime-local][disabled], 738 | .pure-form input[type=week][disabled], 739 | .pure-form input[type=number][disabled], 740 | .pure-form input[type=search][disabled], 741 | .pure-form input[type=tel][disabled], 742 | .pure-form input[type=color][disabled], 743 | .pure-form select[disabled], 744 | .pure-form textarea[disabled] { 745 | cursor: not-allowed; 746 | background-color: #eaeded; 747 | color: #cad2d3; 748 | } 749 | 750 | .pure-form input:not([type])[disabled] { 751 | cursor: not-allowed; 752 | background-color: #eaeded; 753 | color: #cad2d3; 754 | } 755 | 756 | .pure-form input[readonly], 757 | .pure-form select[readonly], 758 | .pure-form textarea[readonly] { 759 | background: #eee; 760 | color: #777; 761 | border-color: #ccc; 762 | } 763 | 764 | .pure-form input:focus:invalid, 765 | .pure-form textarea:focus:invalid, 766 | .pure-form select:focus:invalid { 767 | color: #b94a48; 768 | border-color: #ee5f5b; 769 | } 770 | 771 | .pure-form input:focus:invalid:focus, 772 | .pure-form textarea:focus:invalid:focus, 773 | .pure-form select:focus:invalid:focus { 774 | border-color: #e9322d; 775 | } 776 | 777 | .pure-form input[type=file]:focus:invalid:focus, 778 | .pure-form input[type=radio]:focus:invalid:focus, 779 | .pure-form input[type=checkbox]:focus:invalid:focus { 780 | outline-color: #e9322d; 781 | } 782 | 783 | .pure-form select { 784 | border: 1px solid #ccc; 785 | background-color: #fff; 786 | } 787 | 788 | .pure-form select[multiple] { 789 | height: auto; 790 | } 791 | 792 | .pure-form label { 793 | margin: .5em 0 .2em; 794 | } 795 | 796 | .pure-form fieldset { 797 | margin: 0; 798 | padding: .35em 0 .75em; 799 | border: 0; 800 | } 801 | 802 | .pure-form legend { 803 | display: block; 804 | width: 100%; 805 | padding: .3em 0; 806 | margin-bottom: .3em; 807 | color: #333; 808 | border-bottom: 1px solid #e5e5e5; 809 | } 810 | 811 | .pure-form-stacked input[type=text], 812 | .pure-form-stacked input[type=password], 813 | .pure-form-stacked input[type=email], 814 | .pure-form-stacked input[type=url], 815 | .pure-form-stacked input[type=date], 816 | .pure-form-stacked input[type=month], 817 | .pure-form-stacked input[type=time], 818 | .pure-form-stacked input[type=datetime], 819 | .pure-form-stacked input[type=datetime-local], 820 | .pure-form-stacked input[type=week], 821 | .pure-form-stacked input[type=number], 822 | .pure-form-stacked input[type=search], 823 | .pure-form-stacked input[type=tel], 824 | .pure-form-stacked input[type=color], 825 | .pure-form-stacked select, 826 | .pure-form-stacked label, 827 | .pure-form-stacked textarea { 828 | display: block; 829 | margin: .25em 0; 830 | } 831 | 832 | .pure-form-stacked input:not([type]) { 833 | display: block; 834 | margin: .25em 0; 835 | } 836 | 837 | .pure-form-aligned input, 838 | .pure-form-aligned textarea, 839 | .pure-form-aligned select, 840 | .pure-form-aligned .pure-help-inline, 841 | .pure-form-message-inline { 842 | display: inline-block; 843 | *display: inline; 844 | *zoom: 1; 845 | vertical-align: middle; 846 | } 847 | 848 | .pure-form-aligned textarea { 849 | vertical-align: top; 850 | } 851 | 852 | .pure-form-aligned .pure-control-group { 853 | margin-bottom: .5em; 854 | } 855 | 856 | .pure-form-aligned .pure-control-group label { 857 | text-align: right; 858 | display: inline-block; 859 | vertical-align: middle; 860 | width: 10em; 861 | margin: 0 1em 0 0; 862 | } 863 | 864 | .pure-form-aligned .pure-controls { 865 | margin: 1.5em 0 0 10em; 866 | } 867 | 868 | .pure-form input.pure-input-rounded, 869 | .pure-form .pure-input-rounded { 870 | border-radius: 2em; 871 | padding: .5em 1em; 872 | } 873 | 874 | .pure-form .pure-group fieldset { 875 | margin-bottom: 10px; 876 | } 877 | 878 | .pure-form .pure-group input { 879 | display: block; 880 | padding: 10px; 881 | margin: 0; 882 | border-radius: 0; 883 | position: relative; 884 | top: -1px; 885 | } 886 | 887 | .pure-form .pure-group input:focus { 888 | z-index: 2; 889 | } 890 | 891 | .pure-form .pure-group input:first-child { 892 | top: 1px; 893 | border-radius: 4px 4px 0 0; 894 | } 895 | 896 | .pure-form .pure-group input:last-child { 897 | top: -2px; 898 | border-radius: 0 0 4px 4px; 899 | } 900 | 901 | .pure-form .pure-group button { 902 | margin: .35em 0; 903 | } 904 | 905 | .pure-form .pure-input-1 { 906 | width: 100%; 907 | } 908 | 909 | .pure-form .pure-input-2-3 { 910 | width: 66%; 911 | } 912 | 913 | .pure-form .pure-input-1-2 { 914 | width: 50%; 915 | } 916 | 917 | .pure-form .pure-input-1-3 { 918 | width: 33%; 919 | } 920 | 921 | .pure-form .pure-input-1-4 { 922 | width: 25%; 923 | } 924 | 925 | .pure-form .pure-help-inline, 926 | .pure-form-message-inline { 927 | display: inline-block; 928 | padding-left: .3em; 929 | color: #666; 930 | vertical-align: middle; 931 | font-size: .875em; 932 | } 933 | 934 | .pure-form-message { 935 | display: block; 936 | color: #666; 937 | font-size: .875em; 938 | } 939 | 940 | .pure-menu ul { 941 | position: absolute; 942 | visibility: hidden; 943 | } 944 | 945 | .pure-menu.pure-menu-open { 946 | visibility: visible; 947 | z-index: 2; 948 | width: 100%; 949 | } 950 | 951 | .pure-menu ul { 952 | left: -10000px; 953 | list-style: none; 954 | margin: 0; 955 | padding: 0; 956 | top: -10000px; 957 | z-index: 1; 958 | } 959 | 960 | .pure-menu > ul { 961 | position: relative; 962 | } 963 | 964 | .pure-menu-open > ul { 965 | left: 0; 966 | top: 0; 967 | visibility: visible; 968 | } 969 | 970 | .pure-menu-open > ul:focus { 971 | outline: 0; 972 | } 973 | 974 | .pure-menu li { 975 | position: relative; 976 | } 977 | 978 | .pure-menu a, 979 | .pure-menu .pure-menu-heading { 980 | display: block; 981 | color: inherit; 982 | line-height: 1.5em; 983 | padding: 5px 20px; 984 | text-decoration: none; 985 | white-space: nowrap; 986 | } 987 | 988 | .pure-menu.pure-menu-horizontal > .pure-menu-heading { 989 | display: inline-block; 990 | *display: inline; 991 | zoom: 1; 992 | margin: 0; 993 | vertical-align: middle; 994 | } 995 | 996 | .pure-menu.pure-menu-horizontal > ul { 997 | display: inline-block; 998 | *display: inline; 999 | zoom: 1; 1000 | vertical-align: middle; 1001 | } 1002 | 1003 | .pure-menu li a { 1004 | padding: 5px 20px; 1005 | } 1006 | 1007 | .pure-menu-can-have-children > .pure-menu-label:after { 1008 | content: '\25B8'; 1009 | float: right; 1010 | font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'DejaVu Sans', sans-serif; 1011 | margin-right: -20px; 1012 | margin-top: -1px; 1013 | } 1014 | 1015 | .pure-menu-can-have-children > .pure-menu-label { 1016 | padding-right: 30px; 1017 | } 1018 | 1019 | .pure-menu-separator { 1020 | background-color: #dfdfdf; 1021 | display: block; 1022 | height: 1px; 1023 | font-size: 0; 1024 | margin: 7px 2px; 1025 | overflow: hidden; 1026 | } 1027 | 1028 | .pure-menu-hidden { 1029 | display: none; 1030 | } 1031 | 1032 | .pure-menu-fixed { 1033 | position: fixed; 1034 | top: 0; 1035 | left: 0; 1036 | width: 100%; 1037 | } 1038 | 1039 | .pure-menu-horizontal li { 1040 | display: inline-block; 1041 | *display: inline; 1042 | zoom: 1; 1043 | vertical-align: middle; 1044 | } 1045 | 1046 | .pure-menu-horizontal li li { 1047 | display: block; 1048 | } 1049 | 1050 | .pure-menu-horizontal > .pure-menu-children > .pure-menu-can-have-children > .pure-menu-label:after { 1051 | content: "\25BE"; 1052 | } 1053 | 1054 | .pure-menu-horizontal > .pure-menu-children > .pure-menu-can-have-children > .pure-menu-label { 1055 | padding-right: 30px; 1056 | } 1057 | 1058 | .pure-menu-horizontal li.pure-menu-separator { 1059 | height: 50%; 1060 | width: 1px; 1061 | margin: 0 7px; 1062 | } 1063 | 1064 | .pure-menu-horizontal li li.pure-menu-separator { 1065 | height: 1px; 1066 | width: auto; 1067 | margin: 7px 2px; 1068 | } 1069 | 1070 | .pure-menu.pure-menu-open, 1071 | .pure-menu.pure-menu-horizontal li .pure-menu-children { 1072 | background: #fff; 1073 | border: 1px solid #b7b7b7; 1074 | } 1075 | 1076 | .pure-menu.pure-menu-horizontal, 1077 | .pure-menu.pure-menu-horizontal .pure-menu-heading { 1078 | border: 0; 1079 | } 1080 | 1081 | .pure-menu a { 1082 | border: 1px solid transparent; 1083 | border-left: 0; 1084 | border-right: 0; 1085 | } 1086 | 1087 | .pure-menu a, 1088 | .pure-menu .pure-menu-can-have-children > li:after { 1089 | color: #777; 1090 | } 1091 | 1092 | .pure-menu .pure-menu-can-have-children > li:hover:after { 1093 | color: #fff; 1094 | } 1095 | 1096 | .pure-menu .pure-menu-open { 1097 | background: #dedede; 1098 | } 1099 | 1100 | .pure-menu li a:hover, 1101 | .pure-menu li a:focus { 1102 | background: #eee; 1103 | } 1104 | 1105 | .pure-menu li.pure-menu-disabled a:hover, 1106 | .pure-menu li.pure-menu-disabled a:focus { 1107 | background: #fff; 1108 | color: #bfbfbf; 1109 | } 1110 | 1111 | .pure-menu .pure-menu-disabled > a { 1112 | background-image: none; 1113 | border-color: transparent; 1114 | cursor: default; 1115 | } 1116 | 1117 | .pure-menu .pure-menu-disabled > a, 1118 | .pure-menu .pure-menu-can-have-children.pure-menu-disabled > a:after { 1119 | color: #bfbfbf; 1120 | } 1121 | 1122 | .pure-menu .pure-menu-heading { 1123 | color: #565d64; 1124 | text-transform: uppercase; 1125 | font-size: 90%; 1126 | margin-top: .5em; 1127 | border-bottom-width: 1px; 1128 | border-bottom-style: solid; 1129 | border-bottom-color: #dfdfdf; 1130 | } 1131 | 1132 | .pure-menu .pure-menu-selected a { 1133 | color: #000; 1134 | } 1135 | 1136 | .pure-menu.pure-menu-open.pure-menu-fixed { 1137 | border: 0; 1138 | border-bottom: 1px solid #b7b7b7; 1139 | } 1140 | 1141 | .pure-paginator { 1142 | letter-spacing: -.31em; 1143 | *letter-spacing: normal; 1144 | *word-spacing: -.43em; 1145 | text-rendering: optimizespeed; 1146 | list-style: none; 1147 | margin: 0; 1148 | padding: 0; 1149 | } 1150 | 1151 | .opera-only :-o-prefocus, 1152 | .pure-paginator { 1153 | word-spacing: -.43em; 1154 | } 1155 | 1156 | .pure-paginator li { 1157 | display: inline-block; 1158 | *display: inline; 1159 | zoom: 1; 1160 | letter-spacing: normal; 1161 | word-spacing: normal; 1162 | vertical-align: top; 1163 | text-rendering: auto; 1164 | } 1165 | 1166 | .pure-paginator .pure-button { 1167 | border-radius: 0; 1168 | padding: .8em 1.4em; 1169 | vertical-align: top; 1170 | height: 1.1em; 1171 | } 1172 | 1173 | .pure-paginator .pure-button:focus, 1174 | .pure-paginator .pure-button:active { 1175 | outline-style: none; 1176 | } 1177 | 1178 | .pure-paginator .prev, 1179 | .pure-paginator .next { 1180 | color: #C0C1C3; 1181 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .45); 1182 | } 1183 | 1184 | .pure-paginator .prev { 1185 | border-radius: 2px 0 0 2px; 1186 | } 1187 | 1188 | .pure-paginator .next { 1189 | border-radius: 0 2px 2px 0; 1190 | } 1191 | 1192 | .pure-table { 1193 | border-collapse: collapse; 1194 | border-spacing: 0; 1195 | empty-cells: show; 1196 | border: 1px solid #cbcbcb; 1197 | } 1198 | 1199 | .pure-table caption { 1200 | color: #000; 1201 | font: italic 85%/1 arial, sans-serif; 1202 | padding: 1em 0; 1203 | text-align: center; 1204 | } 1205 | 1206 | .pure-table td, 1207 | .pure-table th { 1208 | border-left: 1px solid #cbcbcb; 1209 | border-width: 0 0 0 1px; 1210 | font-size: inherit; 1211 | margin: 0; 1212 | overflow: visible; 1213 | padding: .5em 1em; 1214 | } 1215 | 1216 | .pure-table td:first-child, 1217 | .pure-table th:first-child { 1218 | border-left-width: 0; 1219 | } 1220 | 1221 | .pure-table thead { 1222 | background: #e0e0e0; 1223 | color: #000; 1224 | text-align: left; 1225 | vertical-align: bottom; 1226 | } 1227 | 1228 | .pure-table td { 1229 | background-color: transparent; 1230 | } 1231 | 1232 | .pure-table-odd td { 1233 | background-color: #f2f2f2; 1234 | } 1235 | 1236 | .pure-table-striped tr:nth-child(2n-1) td { 1237 | background-color: #f2f2f2; 1238 | } 1239 | 1240 | .pure-table-bordered td { 1241 | border-bottom: 1px solid #cbcbcb; 1242 | } 1243 | 1244 | .pure-table-bordered tbody > tr:last-child td, 1245 | .pure-table-horizontal tbody > tr:last-child td { 1246 | border-bottom-width: 0; 1247 | } 1248 | 1249 | .pure-table-horizontal td, 1250 | .pure-table-horizontal th { 1251 | border-width: 0 0 1px; 1252 | border-bottom: 1px solid #cbcbcb; 1253 | } 1254 | 1255 | .pure-table-horizontal tbody > tr:last-child td { 1256 | border-bottom-width: 0; 1257 | } -------------------------------------------------------------------------------- /tests/expected/pure_2.css: -------------------------------------------------------------------------------- 1 | @media only screen and (max-width: 480px) { 2 | .pure-form button[type=submit] { 3 | margin: .7em 0 0; 4 | } 5 | 6 | .pure-form input:not([type]), 7 | .pure-form input[type=text], 8 | .pure-form input[type=password], 9 | .pure-form input[type=email], 10 | .pure-form input[type=url], 11 | .pure-form input[type=date], 12 | .pure-form input[type=month], 13 | .pure-form input[type=time], 14 | .pure-form input[type=datetime], 15 | .pure-form input[type=datetime-local], 16 | .pure-form input[type=week], 17 | .pure-form input[type=number], 18 | .pure-form input[type=search], 19 | .pure-form input[type=tel], 20 | .pure-form input[type=color], 21 | .pure-form label { 22 | margin-bottom: .3em; 23 | display: block; 24 | } 25 | 26 | .pure-group input:not([type]), 27 | .pure-group input[type=text], 28 | .pure-group input[type=password], 29 | .pure-group input[type=email], 30 | .pure-group input[type=url], 31 | .pure-group input[type=date], 32 | .pure-group input[type=month], 33 | .pure-group input[type=time], 34 | .pure-group input[type=datetime], 35 | .pure-group input[type=datetime-local], 36 | .pure-group input[type=week], 37 | .pure-group input[type=number], 38 | .pure-group input[type=search], 39 | .pure-group input[type=tel], 40 | .pure-group input[type=color] { 41 | margin-bottom: 0; 42 | } 43 | 44 | .pure-form-aligned .pure-control-group label { 45 | margin-bottom: .3em; 46 | text-align: left; 47 | display: block; 48 | width: 100%; 49 | } 50 | 51 | .pure-form-aligned .pure-controls { 52 | margin: 1.5em 0 0; 53 | } 54 | 55 | .pure-form .pure-help-inline, 56 | .pure-form-message-inline, 57 | .pure-form-message { 58 | display: block; 59 | font-size: .75em; 60 | padding: .2em 0 .8em; 61 | } 62 | } 63 | 64 | @media (max-width: 480px) { 65 | .pure-menu-horizontal { 66 | width: 100%; 67 | } 68 | 69 | .pure-menu-children li { 70 | display: block; 71 | border-bottom: 1px solid #000; 72 | } 73 | } -------------------------------------------------------------------------------- /tests/fixtures/charset.css: -------------------------------------------------------------------------------- 1 | @charset 'UTF-8'; 2 | 3 | .base { 4 | font-family: "ヒラギノ角ゴ Pro W3", "Hiragino Kaku Gothic Pro", Osaka 5 | } 6 | 7 | .pure-img { 8 | max-width: 100%; 9 | height: auto; 10 | display: block 11 | } 12 | 13 | .pure-button { 14 | -ms-user-select: none; 15 | user-select: none 16 | } 17 | 18 | .pure-button { 19 | border-radius: 2px 20 | } 21 | 22 | .pure-button:focus { 23 | outline: 0 24 | } 25 | 26 | .pure-button-active, .pure-button:active { 27 | box-shadow: 0 0 0 1px rgba(0, 0, 0, .15) inset, 0 0 6px rgba(0, 0, 0, .2) inset 28 | } 29 | -------------------------------------------------------------------------------- /tests/fixtures/imports.css: -------------------------------------------------------------------------------- 1 | @import 'one.css'; 2 | @import 'two.css'; 3 | @import 'three.css'; 4 | @import 'four.css'; 5 | @import 'five.css'; 6 | @import 'six.css'; 7 | @import 'seven.css'; 8 | @import 'eight.css'; 9 | @import 'nine.css'; 10 | -------------------------------------------------------------------------------- /tests/fixtures/pure.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v0.5.0 3 | Copyright 2014 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | https://github.com/yui/pure/blob/master/LICENSE.md 6 | */ 7 | /*! 8 | normalize.css v1.1.3 | MIT License | git.io/normalize 9 | Copyright (c) Nicolas Gallagher and Jonathan Neal 10 | */ 11 | /*! normalize.css v1.1.3 | MIT License | git.io/normalize */ 12 | article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { 13 | display: block 14 | } 15 | 16 | audio, canvas, video { 17 | display: inline-block; 18 | *display: inline; 19 | *zoom: 1 20 | } 21 | 22 | audio:not([controls]) { 23 | display: none; 24 | height: 0 25 | } 26 | 27 | [hidden] { 28 | display: none 29 | } 30 | 31 | html { 32 | font-size: 100%; 33 | -ms-text-size-adjust: 100%; 34 | -webkit-text-size-adjust: 100% 35 | } 36 | 37 | html, button, input, select, textarea { 38 | font-family: sans-serif 39 | } 40 | 41 | body { 42 | margin: 0 43 | } 44 | 45 | a:focus { 46 | outline: thin dotted 47 | } 48 | 49 | a:active, a:hover { 50 | outline: 0 51 | } 52 | 53 | h1 { 54 | font-size: 2em; 55 | margin: .67em 0 56 | } 57 | 58 | h2 { 59 | font-size: 1.5em; 60 | margin: .83em 0 61 | } 62 | 63 | h3 { 64 | font-size: 1.17em; 65 | margin: 1em 0 66 | } 67 | 68 | h4 { 69 | font-size: 1em; 70 | margin: 1.33em 0 71 | } 72 | 73 | h5 { 74 | font-size: .83em; 75 | margin: 1.67em 0 76 | } 77 | 78 | h6 { 79 | font-size: .67em; 80 | margin: 2.33em 0 81 | } 82 | 83 | abbr[title] { 84 | border-bottom: 1px dotted 85 | } 86 | 87 | b, strong { 88 | font-weight: 700 89 | } 90 | 91 | blockquote { 92 | margin: 1em 40px 93 | } 94 | 95 | dfn { 96 | font-style: italic 97 | } 98 | 99 | hr { 100 | -moz-box-sizing: content-box; 101 | box-sizing: content-box; 102 | height: 0 103 | } 104 | 105 | mark { 106 | background: #ff0; 107 | color: #000 108 | } 109 | 110 | p, pre { 111 | margin: 1em 0 112 | } 113 | 114 | code, kbd, pre, samp { 115 | font-family: monospace, serif; 116 | _font-family: 'courier new', monospace; 117 | font-size: 1em 118 | } 119 | 120 | pre { 121 | white-space: pre; 122 | white-space: pre-wrap; 123 | word-wrap: break-word 124 | } 125 | 126 | q { 127 | quotes: none 128 | } 129 | 130 | q:before, q:after { 131 | content: ''; 132 | content: none 133 | } 134 | 135 | small { 136 | font-size: 80% 137 | } 138 | 139 | sub, sup { 140 | font-size: 75%; 141 | line-height: 0; 142 | position: relative; 143 | vertical-align: baseline 144 | } 145 | 146 | sup { 147 | top: -.5em 148 | } 149 | 150 | sub { 151 | bottom: -.25em 152 | } 153 | 154 | dl, menu, ol, ul { 155 | margin: 1em 0 156 | } 157 | 158 | dd { 159 | margin: 0 0 0 40px 160 | } 161 | 162 | menu, ol, ul { 163 | padding: 0 0 0 40px 164 | } 165 | 166 | nav ul, nav ol { 167 | list-style: none; 168 | list-style-image: none 169 | } 170 | 171 | img { 172 | border: 0; 173 | -ms-interpolation-mode: bicubic 174 | } 175 | 176 | svg:not(:root) { 177 | overflow: hidden 178 | } 179 | 180 | figure { 181 | margin: 0 182 | } 183 | 184 | form { 185 | margin: 0 186 | } 187 | 188 | fieldset { 189 | border: 1px solid silver; 190 | margin: 0 2px; 191 | padding: .35em .625em .75em 192 | } 193 | 194 | legend { 195 | border: 0; 196 | padding: 0; 197 | white-space: normal; 198 | *margin-left: -7px 199 | } 200 | 201 | button, input, select, textarea { 202 | font-size: 100%; 203 | margin: 0; 204 | vertical-align: baseline; 205 | *vertical-align: middle 206 | } 207 | 208 | button, input { 209 | line-height: normal 210 | } 211 | 212 | button, select { 213 | text-transform: none 214 | } 215 | 216 | button, html input[type=button], input[type=reset], input[type=submit] { 217 | -webkit-appearance: button; 218 | cursor: pointer; 219 | *overflow: visible 220 | } 221 | 222 | button[disabled], html input[disabled] { 223 | cursor: default 224 | } 225 | 226 | input[type=checkbox], input[type=radio] { 227 | box-sizing: border-box; 228 | padding: 0; 229 | *height: 13px; 230 | *width: 13px 231 | } 232 | 233 | input[type=search] { 234 | -webkit-appearance: textfield; 235 | -moz-box-sizing: content-box; 236 | -webkit-box-sizing: content-box; 237 | box-sizing: content-box 238 | } 239 | 240 | input[type=search]::-webkit-search-cancel-button, input[type=search]::-webkit-search-decoration { 241 | -webkit-appearance: none 242 | } 243 | 244 | button::-moz-focus-inner, input::-moz-focus-inner { 245 | border: 0; 246 | padding: 0 247 | } 248 | 249 | textarea { 250 | overflow: auto; 251 | vertical-align: top 252 | } 253 | 254 | table { 255 | border-collapse: collapse; 256 | border-spacing: 0 257 | } 258 | 259 | [hidden] { 260 | display: none !important 261 | } 262 | 263 | .pure-img { 264 | max-width: 100%; 265 | height: auto; 266 | display: block 267 | } 268 | 269 | .pure-g { 270 | letter-spacing: -.31em; 271 | *letter-spacing: normal; 272 | *word-spacing: -.43em; 273 | text-rendering: optimizespeed; 274 | font-family: FreeSans, Arimo, "Droid Sans", Helvetica, Arial, sans-serif; 275 | display: -webkit-flex; 276 | -webkit-flex-flow: row wrap; 277 | display: -ms-flexbox; 278 | -ms-flex-flow: row wrap 279 | } 280 | 281 | .opera-only :-o-prefocus, .pure-g { 282 | word-spacing: -.43em 283 | } 284 | 285 | .pure-u { 286 | display: inline-block; 287 | *display: inline; 288 | zoom: 1; 289 | letter-spacing: normal; 290 | word-spacing: normal; 291 | vertical-align: top; 292 | text-rendering: auto 293 | } 294 | 295 | .pure-g [class *="pure-u"] { 296 | font-family: sans-serif 297 | } 298 | 299 | .pure-u-1, .pure-u-1-1, .pure-u-1-2, .pure-u-1-3, .pure-u-2-3, .pure-u-1-4, .pure-u-3-4, .pure-u-1-5, .pure-u-2-5, .pure-u-3-5, .pure-u-4-5, .pure-u-5-5, .pure-u-1-6, .pure-u-5-6, .pure-u-1-8, .pure-u-3-8, .pure-u-5-8, .pure-u-7-8, .pure-u-1-12, .pure-u-5-12, .pure-u-7-12, .pure-u-11-12, .pure-u-1-24, .pure-u-2-24, .pure-u-3-24, .pure-u-4-24, .pure-u-5-24, .pure-u-6-24, .pure-u-7-24, .pure-u-8-24, .pure-u-9-24, .pure-u-10-24, .pure-u-11-24, .pure-u-12-24, .pure-u-13-24, .pure-u-14-24, .pure-u-15-24, .pure-u-16-24, .pure-u-17-24, .pure-u-18-24, .pure-u-19-24, .pure-u-20-24, .pure-u-21-24, .pure-u-22-24, .pure-u-23-24, .pure-u-24-24 { 300 | display: inline-block; 301 | *display: inline; 302 | zoom: 1; 303 | letter-spacing: normal; 304 | word-spacing: normal; 305 | vertical-align: top; 306 | text-rendering: auto 307 | } 308 | 309 | .pure-u-1-24 { 310 | width: 4.1667%; 311 | *width: 4.1357% 312 | } 313 | 314 | .pure-u-1-12, .pure-u-2-24 { 315 | width: 8.3333%; 316 | *width: 8.3023% 317 | } 318 | 319 | .pure-u-1-8, .pure-u-3-24 { 320 | width: 12.5%; 321 | *width: 12.469% 322 | } 323 | 324 | .pure-u-1-6, .pure-u-4-24 { 325 | width: 16.6667%; 326 | *width: 16.6357% 327 | } 328 | 329 | .pure-u-1-5 { 330 | width: 20%; 331 | *width: 19.969% 332 | } 333 | 334 | .pure-u-5-24 { 335 | width: 20.8333%; 336 | *width: 20.8023% 337 | } 338 | 339 | .pure-u-1-4, .pure-u-6-24 { 340 | width: 25%; 341 | *width: 24.969% 342 | } 343 | 344 | .pure-u-7-24 { 345 | width: 29.1667%; 346 | *width: 29.1357% 347 | } 348 | 349 | .pure-u-1-3, .pure-u-8-24 { 350 | width: 33.3333%; 351 | *width: 33.3023% 352 | } 353 | 354 | .pure-u-3-8, .pure-u-9-24 { 355 | width: 37.5%; 356 | *width: 37.469% 357 | } 358 | 359 | .pure-u-2-5 { 360 | width: 40%; 361 | *width: 39.969% 362 | } 363 | 364 | .pure-u-5-12, .pure-u-10-24 { 365 | width: 41.6667%; 366 | *width: 41.6357% 367 | } 368 | 369 | .pure-u-11-24 { 370 | width: 45.8333%; 371 | *width: 45.8023% 372 | } 373 | 374 | .pure-u-1-2, .pure-u-12-24 { 375 | width: 50%; 376 | *width: 49.969% 377 | } 378 | 379 | .pure-u-13-24 { 380 | width: 54.1667%; 381 | *width: 54.1357% 382 | } 383 | 384 | .pure-u-7-12, .pure-u-14-24 { 385 | width: 58.3333%; 386 | *width: 58.3023% 387 | } 388 | 389 | .pure-u-3-5 { 390 | width: 60%; 391 | *width: 59.969% 392 | } 393 | 394 | .pure-u-5-8, .pure-u-15-24 { 395 | width: 62.5%; 396 | *width: 62.469% 397 | } 398 | 399 | .pure-u-2-3, .pure-u-16-24 { 400 | width: 66.6667%; 401 | *width: 66.6357% 402 | } 403 | 404 | .pure-u-17-24 { 405 | width: 70.8333%; 406 | *width: 70.8023% 407 | } 408 | 409 | .pure-u-3-4, .pure-u-18-24 { 410 | width: 75%; 411 | *width: 74.969% 412 | } 413 | 414 | .pure-u-19-24 { 415 | width: 79.1667%; 416 | *width: 79.1357% 417 | } 418 | 419 | .pure-u-4-5 { 420 | width: 80%; 421 | *width: 79.969% 422 | } 423 | 424 | .pure-u-5-6, .pure-u-20-24 { 425 | width: 83.3333%; 426 | *width: 83.3023% 427 | } 428 | 429 | .pure-u-7-8, .pure-u-21-24 { 430 | width: 87.5%; 431 | *width: 87.469% 432 | } 433 | 434 | .pure-u-11-12, .pure-u-22-24 { 435 | width: 91.6667%; 436 | *width: 91.6357% 437 | } 438 | 439 | .pure-u-23-24 { 440 | width: 95.8333%; 441 | *width: 95.8023% 442 | } 443 | 444 | .pure-u-1, .pure-u-1-1, .pure-u-5-5, .pure-u-24-24 { 445 | width: 100% 446 | } 447 | 448 | .pure-button { 449 | display: inline-block; 450 | *display: inline; 451 | zoom: 1; 452 | line-height: normal; 453 | white-space: nowrap; 454 | vertical-align: baseline; 455 | text-align: center; 456 | cursor: pointer; 457 | -webkit-user-drag: none; 458 | -webkit-user-select: none; 459 | -moz-user-select: none; 460 | -ms-user-select: none; 461 | user-select: none 462 | } 463 | 464 | .pure-button::-moz-focus-inner { 465 | padding: 0; 466 | border: 0 467 | } 468 | 469 | .pure-button { 470 | font-family: inherit; 471 | font-size: 100%; 472 | *font-size: 90%; 473 | *overflow: visible; 474 | padding: .5em 1em; 475 | color: #444; 476 | color: rgba(0, 0, 0, .8); 477 | *color: #444; 478 | border: 1px solid #999; 479 | border: 0 rgba(0, 0, 0, 0); 480 | background-color: #E6E6E6; 481 | text-decoration: none; 482 | border-radius: 2px 483 | } 484 | 485 | .pure-button-hover, .pure-button:hover, .pure-button:focus { 486 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000', GradientType=0); 487 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(transparent), color-stop(40%, rgba(0, 0, 0, .05)), to(rgba(0, 0, 0, .1))); 488 | background-image: -webkit-linear-gradient(transparent, rgba(0, 0, 0, .05) 40%, rgba(0, 0, 0, .1)); 489 | background-image: -moz-linear-gradient(top, rgba(0, 0, 0, .05) 0, rgba(0, 0, 0, .1)); 490 | background-image: -o-linear-gradient(transparent, rgba(0, 0, 0, .05) 40%, rgba(0, 0, 0, .1)); 491 | background-image: linear-gradient(transparent, rgba(0, 0, 0, .05) 40%, rgba(0, 0, 0, .1)) 492 | } 493 | 494 | .pure-button:focus { 495 | outline: 0 496 | } 497 | 498 | .pure-button-active, .pure-button:active { 499 | box-shadow: 0 0 0 1px rgba(0, 0, 0, .15) inset, 0 0 6px rgba(0, 0, 0, .2) inset 500 | } 501 | 502 | .pure-button[disabled], .pure-button-disabled, .pure-button-disabled:hover, .pure-button-disabled:focus, .pure-button-disabled:active { 503 | border: 0; 504 | background-image: none; 505 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 506 | filter: alpha(opacity=40); 507 | -khtml-opacity: .4; 508 | -moz-opacity: .4; 509 | opacity: .4; 510 | cursor: not-allowed; 511 | box-shadow: none 512 | } 513 | 514 | .pure-button-hidden { 515 | display: none 516 | } 517 | 518 | .pure-button::-moz-focus-inner { 519 | padding: 0; 520 | border: 0 521 | } 522 | 523 | .pure-button-primary, .pure-button-selected, a.pure-button-primary, a.pure-button-selected { 524 | background-color: #0078e7; 525 | color: #fff 526 | } 527 | 528 | .pure-form input[type=text], .pure-form input[type=password], .pure-form input[type=email], .pure-form input[type=url], .pure-form input[type=date], .pure-form input[type=month], .pure-form input[type=time], .pure-form input[type=datetime], .pure-form input[type=datetime-local], .pure-form input[type=week], .pure-form input[type=number], .pure-form input[type=search], .pure-form input[type=tel], .pure-form input[type=color], .pure-form select, .pure-form textarea { 529 | padding: .5em .6em; 530 | display: inline-block; 531 | border: 1px solid #ccc; 532 | box-shadow: inset 0 1px 3px #ddd; 533 | border-radius: 4px; 534 | -webkit-box-sizing: border-box; 535 | -moz-box-sizing: border-box; 536 | box-sizing: border-box 537 | } 538 | 539 | .pure-form input:not([type]) { 540 | padding: .5em .6em; 541 | display: inline-block; 542 | border: 1px solid #ccc; 543 | box-shadow: inset 0 1px 3px #ddd; 544 | border-radius: 4px; 545 | -webkit-box-sizing: border-box; 546 | -moz-box-sizing: border-box; 547 | box-sizing: border-box 548 | } 549 | 550 | .pure-form input[type=color] { 551 | padding: .2em .5em 552 | } 553 | 554 | .pure-form input[type=text]:focus, .pure-form input[type=password]:focus, .pure-form input[type=email]:focus, .pure-form input[type=url]:focus, .pure-form input[type=date]:focus, .pure-form input[type=month]:focus, .pure-form input[type=time]:focus, .pure-form input[type=datetime]:focus, .pure-form input[type=datetime-local]:focus, .pure-form input[type=week]:focus, .pure-form input[type=number]:focus, .pure-form input[type=search]:focus, .pure-form input[type=tel]:focus, .pure-form input[type=color]:focus, .pure-form select:focus, .pure-form textarea:focus { 555 | outline: 0; 556 | outline: thin dotted \9; 557 | border-color: #129FEA 558 | } 559 | 560 | .pure-form input:not([type]):focus { 561 | outline: 0; 562 | outline: thin dotted \9; 563 | border-color: #129FEA 564 | } 565 | 566 | .pure-form input[type=file]:focus, .pure-form input[type=radio]:focus, .pure-form input[type=checkbox]:focus { 567 | outline: thin dotted #333; 568 | outline: 1px auto #129FEA 569 | } 570 | 571 | .pure-form .pure-checkbox, .pure-form .pure-radio { 572 | margin: .5em 0; 573 | display: block 574 | } 575 | 576 | .pure-form input[type=text][disabled], .pure-form input[type=password][disabled], .pure-form input[type=email][disabled], .pure-form input[type=url][disabled], .pure-form input[type=date][disabled], .pure-form input[type=month][disabled], .pure-form input[type=time][disabled], .pure-form input[type=datetime][disabled], .pure-form input[type=datetime-local][disabled], .pure-form input[type=week][disabled], .pure-form input[type=number][disabled], .pure-form input[type=search][disabled], .pure-form input[type=tel][disabled], .pure-form input[type=color][disabled], .pure-form select[disabled], .pure-form textarea[disabled] { 577 | cursor: not-allowed; 578 | background-color: #eaeded; 579 | color: #cad2d3 580 | } 581 | 582 | .pure-form input:not([type])[disabled] { 583 | cursor: not-allowed; 584 | background-color: #eaeded; 585 | color: #cad2d3 586 | } 587 | 588 | .pure-form input[readonly], .pure-form select[readonly], .pure-form textarea[readonly] { 589 | background: #eee; 590 | color: #777; 591 | border-color: #ccc 592 | } 593 | 594 | .pure-form input:focus:invalid, .pure-form textarea:focus:invalid, .pure-form select:focus:invalid { 595 | color: #b94a48; 596 | border-color: #ee5f5b 597 | } 598 | 599 | .pure-form input:focus:invalid:focus, .pure-form textarea:focus:invalid:focus, .pure-form select:focus:invalid:focus { 600 | border-color: #e9322d 601 | } 602 | 603 | .pure-form input[type=file]:focus:invalid:focus, .pure-form input[type=radio]:focus:invalid:focus, .pure-form input[type=checkbox]:focus:invalid:focus { 604 | outline-color: #e9322d 605 | } 606 | 607 | .pure-form select { 608 | border: 1px solid #ccc; 609 | background-color: #fff 610 | } 611 | 612 | .pure-form select[multiple] { 613 | height: auto 614 | } 615 | 616 | .pure-form label { 617 | margin: .5em 0 .2em 618 | } 619 | 620 | .pure-form fieldset { 621 | margin: 0; 622 | padding: .35em 0 .75em; 623 | border: 0 624 | } 625 | 626 | .pure-form legend { 627 | display: block; 628 | width: 100%; 629 | padding: .3em 0; 630 | margin-bottom: .3em; 631 | color: #333; 632 | border-bottom: 1px solid #e5e5e5 633 | } 634 | 635 | .pure-form-stacked input[type=text], .pure-form-stacked input[type=password], .pure-form-stacked input[type=email], .pure-form-stacked input[type=url], .pure-form-stacked input[type=date], .pure-form-stacked input[type=month], .pure-form-stacked input[type=time], .pure-form-stacked input[type=datetime], .pure-form-stacked input[type=datetime-local], .pure-form-stacked input[type=week], .pure-form-stacked input[type=number], .pure-form-stacked input[type=search], .pure-form-stacked input[type=tel], .pure-form-stacked input[type=color], .pure-form-stacked select, .pure-form-stacked label, .pure-form-stacked textarea { 636 | display: block; 637 | margin: .25em 0 638 | } 639 | 640 | .pure-form-stacked input:not([type]) { 641 | display: block; 642 | margin: .25em 0 643 | } 644 | 645 | .pure-form-aligned input, .pure-form-aligned textarea, .pure-form-aligned select, .pure-form-aligned .pure-help-inline, .pure-form-message-inline { 646 | display: inline-block; 647 | *display: inline; 648 | *zoom: 1; 649 | vertical-align: middle 650 | } 651 | 652 | .pure-form-aligned textarea { 653 | vertical-align: top 654 | } 655 | 656 | .pure-form-aligned .pure-control-group { 657 | margin-bottom: .5em 658 | } 659 | 660 | .pure-form-aligned .pure-control-group label { 661 | text-align: right; 662 | display: inline-block; 663 | vertical-align: middle; 664 | width: 10em; 665 | margin: 0 1em 0 0 666 | } 667 | 668 | .pure-form-aligned .pure-controls { 669 | margin: 1.5em 0 0 10em 670 | } 671 | 672 | .pure-form input.pure-input-rounded, .pure-form .pure-input-rounded { 673 | border-radius: 2em; 674 | padding: .5em 1em 675 | } 676 | 677 | .pure-form .pure-group fieldset { 678 | margin-bottom: 10px 679 | } 680 | 681 | .pure-form .pure-group input { 682 | display: block; 683 | padding: 10px; 684 | margin: 0; 685 | border-radius: 0; 686 | position: relative; 687 | top: -1px 688 | } 689 | 690 | .pure-form .pure-group input:focus { 691 | z-index: 2 692 | } 693 | 694 | .pure-form .pure-group input:first-child { 695 | top: 1px; 696 | border-radius: 4px 4px 0 0 697 | } 698 | 699 | .pure-form .pure-group input:last-child { 700 | top: -2px; 701 | border-radius: 0 0 4px 4px 702 | } 703 | 704 | .pure-form .pure-group button { 705 | margin: .35em 0 706 | } 707 | 708 | .pure-form .pure-input-1 { 709 | width: 100% 710 | } 711 | 712 | .pure-form .pure-input-2-3 { 713 | width: 66% 714 | } 715 | 716 | .pure-form .pure-input-1-2 { 717 | width: 50% 718 | } 719 | 720 | .pure-form .pure-input-1-3 { 721 | width: 33% 722 | } 723 | 724 | .pure-form .pure-input-1-4 { 725 | width: 25% 726 | } 727 | 728 | .pure-form .pure-help-inline, .pure-form-message-inline { 729 | display: inline-block; 730 | padding-left: .3em; 731 | color: #666; 732 | vertical-align: middle; 733 | font-size: .875em 734 | } 735 | 736 | .pure-form-message { 737 | display: block; 738 | color: #666; 739 | font-size: .875em 740 | } 741 | 742 | @media only screen and (max-width: 480px) { 743 | .pure-form button[type=submit] { 744 | margin: .7em 0 0 745 | } 746 | 747 | .pure-form input:not([type]), .pure-form input[type=text], .pure-form input[type=password], .pure-form input[type=email], .pure-form input[type=url], .pure-form input[type=date], .pure-form input[type=month], .pure-form input[type=time], .pure-form input[type=datetime], .pure-form input[type=datetime-local], .pure-form input[type=week], .pure-form input[type=number], .pure-form input[type=search], .pure-form input[type=tel], .pure-form input[type=color], .pure-form label { 748 | margin-bottom: .3em; 749 | display: block 750 | } 751 | 752 | .pure-group input:not([type]), .pure-group input[type=text], .pure-group input[type=password], .pure-group input[type=email], .pure-group input[type=url], .pure-group input[type=date], .pure-group input[type=month], .pure-group input[type=time], .pure-group input[type=datetime], .pure-group input[type=datetime-local], .pure-group input[type=week], .pure-group input[type=number], .pure-group input[type=search], .pure-group input[type=tel], .pure-group input[type=color] { 753 | margin-bottom: 0 754 | } 755 | 756 | .pure-form-aligned .pure-control-group label { 757 | margin-bottom: .3em; 758 | text-align: left; 759 | display: block; 760 | width: 100% 761 | } 762 | 763 | .pure-form-aligned .pure-controls { 764 | margin: 1.5em 0 0 765 | } 766 | 767 | .pure-form .pure-help-inline, .pure-form-message-inline, .pure-form-message { 768 | display: block; 769 | font-size: .75em; 770 | padding: .2em 0 .8em 771 | } 772 | } 773 | 774 | .pure-menu ul { 775 | position: absolute; 776 | visibility: hidden 777 | } 778 | 779 | .pure-menu.pure-menu-open { 780 | visibility: visible; 781 | z-index: 2; 782 | width: 100% 783 | } 784 | 785 | .pure-menu ul { 786 | left: -10000px; 787 | list-style: none; 788 | margin: 0; 789 | padding: 0; 790 | top: -10000px; 791 | z-index: 1 792 | } 793 | 794 | .pure-menu > ul { 795 | position: relative 796 | } 797 | 798 | .pure-menu-open > ul { 799 | left: 0; 800 | top: 0; 801 | visibility: visible 802 | } 803 | 804 | .pure-menu-open > ul:focus { 805 | outline: 0 806 | } 807 | 808 | .pure-menu li { 809 | position: relative 810 | } 811 | 812 | .pure-menu a, .pure-menu .pure-menu-heading { 813 | display: block; 814 | color: inherit; 815 | line-height: 1.5em; 816 | padding: 5px 20px; 817 | text-decoration: none; 818 | white-space: nowrap 819 | } 820 | 821 | .pure-menu.pure-menu-horizontal > .pure-menu-heading { 822 | display: inline-block; 823 | *display: inline; 824 | zoom: 1; 825 | margin: 0; 826 | vertical-align: middle 827 | } 828 | 829 | .pure-menu.pure-menu-horizontal > ul { 830 | display: inline-block; 831 | *display: inline; 832 | zoom: 1; 833 | vertical-align: middle 834 | } 835 | 836 | .pure-menu li a { 837 | padding: 5px 20px 838 | } 839 | 840 | .pure-menu-can-have-children > .pure-menu-label:after { 841 | content: '\25B8'; 842 | float: right; 843 | font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'DejaVu Sans', sans-serif; 844 | margin-right: -20px; 845 | margin-top: -1px 846 | } 847 | 848 | .pure-menu-can-have-children > .pure-menu-label { 849 | padding-right: 30px 850 | } 851 | 852 | .pure-menu-separator { 853 | background-color: #dfdfdf; 854 | display: block; 855 | height: 1px; 856 | font-size: 0; 857 | margin: 7px 2px; 858 | overflow: hidden 859 | } 860 | 861 | .pure-menu-hidden { 862 | display: none 863 | } 864 | 865 | .pure-menu-fixed { 866 | position: fixed; 867 | top: 0; 868 | left: 0; 869 | width: 100% 870 | } 871 | 872 | .pure-menu-horizontal li { 873 | display: inline-block; 874 | *display: inline; 875 | zoom: 1; 876 | vertical-align: middle 877 | } 878 | 879 | .pure-menu-horizontal li li { 880 | display: block 881 | } 882 | 883 | .pure-menu-horizontal > .pure-menu-children > .pure-menu-can-have-children > .pure-menu-label:after { 884 | content: "\25BE" 885 | } 886 | 887 | .pure-menu-horizontal > .pure-menu-children > .pure-menu-can-have-children > .pure-menu-label { 888 | padding-right: 30px 889 | } 890 | 891 | .pure-menu-horizontal li.pure-menu-separator { 892 | height: 50%; 893 | width: 1px; 894 | margin: 0 7px 895 | } 896 | 897 | .pure-menu-horizontal li li.pure-menu-separator { 898 | height: 1px; 899 | width: auto; 900 | margin: 7px 2px 901 | } 902 | 903 | .pure-menu.pure-menu-open, .pure-menu.pure-menu-horizontal li .pure-menu-children { 904 | background: #fff; 905 | border: 1px solid #b7b7b7 906 | } 907 | 908 | .pure-menu.pure-menu-horizontal, .pure-menu.pure-menu-horizontal .pure-menu-heading { 909 | border: 0 910 | } 911 | 912 | .pure-menu a { 913 | border: 1px solid transparent; 914 | border-left: 0; 915 | border-right: 0 916 | } 917 | 918 | .pure-menu a, .pure-menu .pure-menu-can-have-children > li:after { 919 | color: #777 920 | } 921 | 922 | .pure-menu .pure-menu-can-have-children > li:hover:after { 923 | color: #fff 924 | } 925 | 926 | .pure-menu .pure-menu-open { 927 | background: #dedede 928 | } 929 | 930 | .pure-menu li a:hover, .pure-menu li a:focus { 931 | background: #eee 932 | } 933 | 934 | .pure-menu li.pure-menu-disabled a:hover, .pure-menu li.pure-menu-disabled a:focus { 935 | background: #fff; 936 | color: #bfbfbf 937 | } 938 | 939 | .pure-menu .pure-menu-disabled > a { 940 | background-image: none; 941 | border-color: transparent; 942 | cursor: default 943 | } 944 | 945 | .pure-menu .pure-menu-disabled > a, .pure-menu .pure-menu-can-have-children.pure-menu-disabled > a:after { 946 | color: #bfbfbf 947 | } 948 | 949 | .pure-menu .pure-menu-heading { 950 | color: #565d64; 951 | text-transform: uppercase; 952 | font-size: 90%; 953 | margin-top: .5em; 954 | border-bottom-width: 1px; 955 | border-bottom-style: solid; 956 | border-bottom-color: #dfdfdf 957 | } 958 | 959 | .pure-menu .pure-menu-selected a { 960 | color: #000 961 | } 962 | 963 | .pure-menu.pure-menu-open.pure-menu-fixed { 964 | border: 0; 965 | border-bottom: 1px solid #b7b7b7 966 | } 967 | 968 | .pure-paginator { 969 | letter-spacing: -.31em; 970 | *letter-spacing: normal; 971 | *word-spacing: -.43em; 972 | text-rendering: optimizespeed; 973 | list-style: none; 974 | margin: 0; 975 | padding: 0 976 | } 977 | 978 | .opera-only :-o-prefocus, .pure-paginator { 979 | word-spacing: -.43em 980 | } 981 | 982 | .pure-paginator li { 983 | display: inline-block; 984 | *display: inline; 985 | zoom: 1; 986 | letter-spacing: normal; 987 | word-spacing: normal; 988 | vertical-align: top; 989 | text-rendering: auto 990 | } 991 | 992 | .pure-paginator .pure-button { 993 | border-radius: 0; 994 | padding: .8em 1.4em; 995 | vertical-align: top; 996 | height: 1.1em 997 | } 998 | 999 | .pure-paginator .pure-button:focus, .pure-paginator .pure-button:active { 1000 | outline-style: none 1001 | } 1002 | 1003 | .pure-paginator .prev, .pure-paginator .next { 1004 | color: #C0C1C3; 1005 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .45) 1006 | } 1007 | 1008 | .pure-paginator .prev { 1009 | border-radius: 2px 0 0 2px 1010 | } 1011 | 1012 | .pure-paginator .next { 1013 | border-radius: 0 2px 2px 0 1014 | } 1015 | 1016 | @media (max-width: 480px) { 1017 | .pure-menu-horizontal { 1018 | width: 100% 1019 | } 1020 | 1021 | .pure-menu-children li { 1022 | display: block; 1023 | border-bottom: 1px solid #000 1024 | } 1025 | } 1026 | 1027 | .pure-table { 1028 | border-collapse: collapse; 1029 | border-spacing: 0; 1030 | empty-cells: show; 1031 | border: 1px solid #cbcbcb 1032 | } 1033 | 1034 | .pure-table caption { 1035 | color: #000; 1036 | font: italic 85%/1 arial, sans-serif; 1037 | padding: 1em 0; 1038 | text-align: center 1039 | } 1040 | 1041 | .pure-table td, .pure-table th { 1042 | border-left: 1px solid #cbcbcb; 1043 | border-width: 0 0 0 1px; 1044 | font-size: inherit; 1045 | margin: 0; 1046 | overflow: visible; 1047 | padding: .5em 1em 1048 | } 1049 | 1050 | .pure-table td:first-child, .pure-table th:first-child { 1051 | border-left-width: 0 1052 | } 1053 | 1054 | .pure-table thead { 1055 | background: #e0e0e0; 1056 | color: #000; 1057 | text-align: left; 1058 | vertical-align: bottom 1059 | } 1060 | 1061 | .pure-table td { 1062 | background-color: transparent 1063 | } 1064 | 1065 | .pure-table-odd td { 1066 | background-color: #f2f2f2 1067 | } 1068 | 1069 | .pure-table-striped tr:nth-child(2n-1) td { 1070 | background-color: #f2f2f2 1071 | } 1072 | 1073 | .pure-table-bordered td { 1074 | border-bottom: 1px solid #cbcbcb 1075 | } 1076 | 1077 | .pure-table-bordered tbody > tr:last-child td, .pure-table-horizontal tbody > tr:last-child td { 1078 | border-bottom-width: 0 1079 | } 1080 | 1081 | .pure-table-horizontal td, .pure-table-horizontal th { 1082 | border-width: 0 0 1px; 1083 | border-bottom: 1px solid #cbcbcb 1084 | } 1085 | 1086 | .pure-table-horizontal tbody > tr:last-child td { 1087 | border-bottom-width: 0 1088 | } -------------------------------------------------------------------------------- /tests/fixtures/twenty.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v0.5.0, reduced to twenty selectors, with media queries 3 | Copyright 2014 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | https://github.com/yui/pure/blob/master/LICENSE.md 6 | */ 7 | 8 | .pure-img { 9 | max-width: 100%; 10 | height: auto; 11 | display: block 12 | } 13 | 14 | .pure-button { 15 | -ms-user-select: none; 16 | user-select: none 17 | } 18 | 19 | .pure-button { 20 | border-radius: 2px 21 | } 22 | 23 | .pure-button:focus { 24 | outline: 0 25 | } 26 | 27 | .pure-button-active, .pure-button:active { 28 | box-shadow: 0 0 0 1px rgba(0, 0, 0, .15) inset, 0 0 6px rgba(0, 0, 0, .2) inset 29 | } 30 | 31 | .pure-button-primary, .pure-button-selected, a.pure-button-primary, a.pure-button-selected { 32 | background-color: #0078e7; 33 | color: #fff 34 | } 35 | 36 | 37 | .pure-menu, .pure-menu-heading { 38 | color: #565d64; 39 | text-transform: uppercase; 40 | font-size: 90%; 41 | margin-top: .5em; 42 | border-bottom-width: 1px; 43 | border-bottom-style: solid; 44 | border-bottom-color: #dfdfdf 45 | } 46 | 47 | .pure-menu, .pure-menu-selected a { 48 | color: #000 49 | } 50 | 51 | .pure-menu.pure-menu-open, .pure-menu-fixed { 52 | border: 0; 53 | border-bottom: 1px solid #b7b7b7 54 | } 55 | 56 | 57 | @media (max-width: 240px) { 58 | .pure-menu-horizontal { 59 | width: 100% 60 | } 61 | 62 | .pure-menu-children li { 63 | display: block; 64 | border-bottom: 1px solid #000 65 | } 66 | } 67 | 68 | @media (max-width: 480px) { 69 | .pure-menu-horizontal { 70 | width: 80% 71 | } 72 | 73 | .pure-menu-children li { 74 | border-bottom: 5px solid #000 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /tests/index_test.js: -------------------------------------------------------------------------------- 1 | /* @flow weak */ 2 | /** 3 | * Sakugawa 4 | * https://github.com/paazmaya/sakugawa 5 | * 6 | * Copyright (c) Juga Paazmaya (https://paazmaya.fi) 7 | * Licensed under the MIT license. 8 | */ 9 | 10 | 11 | const fs = require('fs'); 12 | const tape = require('tape'); 13 | const sakugawa = require('../index'); 14 | 15 | // This CSS file has 5 selectors 16 | const twenty = fs.readFileSync('tests/fixtures/twenty.css', 'utf8'); 17 | 18 | // Helper to save files when creating a new test in order to easily inspect the result 19 | /* 20 | var saveResults = function (results, prefix) { 21 | for (let i = 0; i < results.length; ++i) { 22 | var stuff = results[i]; 23 | fs.writeFileSync(__dirname + '/expected/' + prefix + '_' + (i + 1) + '.css', stuff, 'utf8'); 24 | } 25 | }; 26 | */ 27 | 28 | tape('dummy test', (test) => { 29 | test.plan(2); 30 | 31 | test.equal(typeof sakugawa, 'function'); 32 | 33 | const styles = 'body {\n color: rebeccapurple;\n}'; 34 | test.deepEqual(sakugawa(styles), [styles]); 35 | }); 36 | 37 | tape('max selectors lower than total', (test) => { 38 | test.plan(2); 39 | 40 | const name = 'max-selectors-lower'; 41 | const options = { 42 | maxSelectors: 16 43 | }; 44 | const result = sakugawa(twenty, options); 45 | test.equal(result.length, 2, name); 46 | 47 | const expected1 = fs.readFileSync('tests/expected/' + name + '_1.css', 'utf8'); 48 | test.equal(result[0], expected1, name); 49 | }); 50 | 51 | tape('max selectors higher than total', (test) => { 52 | test.plan(1); 53 | 54 | const name = 'max-selectors-higher'; 55 | const options = { 56 | maxSelectors: 24 57 | }; 58 | const result = sakugawa(twenty, options); 59 | test.equal(result.length, 1); 60 | }); 61 | 62 | tape('max selectors same as total', (test) => { 63 | test.plan(1); 64 | 65 | const name = 'max-selectors-same'; 66 | const options = { 67 | maxSelectors: 20 68 | }; 69 | const result = sakugawa(twenty, options); 70 | test.equal(result.length, 1, name); 71 | }); 72 | 73 | tape('media queries separated', (test) => { 74 | test.plan(1); 75 | 76 | const name = 'media-queries-separated'; 77 | const options = { 78 | maxSelectors: 50, 79 | mediaQueries: 'separate' 80 | }; 81 | const result = sakugawa(twenty, options); 82 | test.equal(result.length, 2, name); 83 | }); 84 | 85 | tape('media queries ignored', (test) => { 86 | test.plan(1); 87 | 88 | const name = 'media-queries-ignored'; 89 | const options = { 90 | maxSelectors: 18, 91 | mediaQueries: 'ignore' 92 | }; 93 | const result = sakugawa(twenty, options); 94 | test.equal(result.length, 1, name); 95 | }); 96 | 97 | /* 98 | tape('filename option gets used', (test) => { 99 | test.plan(1); 100 | 101 | const options = { 102 | filename: 'very-secret.css' 103 | }; 104 | 105 | }); 106 | */ 107 | 108 | tape('two empty files due to minimum number of sheets being high', (test) => { 109 | test.plan(1); 110 | 111 | const name = 'min-sheets-higher'; 112 | const options = { 113 | maxSelectors: 12, 114 | minSheets: 4 115 | }; 116 | const result = sakugawa(twenty, options); 117 | test.equal(result.length, 4, name); 118 | }); 119 | 120 | tape('minSheets irrelevant when lower than resulting number', (test) => { 121 | test.plan(1); 122 | 123 | const name = 'min-sheets-lower'; 124 | const options = { 125 | maxSelectors: 8, 126 | minSheets: 2 127 | }; 128 | const result = sakugawa(twenty, options); 129 | test.equal(result.length, 3, name); 130 | }); 131 | 132 | tape('minSheets irrelevant when same as resulting number', (test) => { 133 | test.plan(1); 134 | 135 | const name = 'min-sheets-same'; 136 | const options = { 137 | maxSelectors: 6, 138 | minSheets: 4 139 | }; 140 | const result = sakugawa(twenty, options); 141 | test.equal(result.length, 4, name); 142 | }); 143 | 144 | tape('error case when no styles empty', (test) => { 145 | test.plan(1); 146 | 147 | try { 148 | const result = sakugawa(''); 149 | } 150 | catch (error) { 151 | test.equal(error.message, 'styles must not be empty'); 152 | } 153 | }); 154 | 155 | tape('error case when styles are not a string', (test) => { 156 | test.plan(1); 157 | 158 | try { 159 | const result = sakugawa(42); 160 | } 161 | catch (error) { 162 | test.equal(error.message, 'styles must be a string'); 163 | } 164 | }); 165 | 166 | tape('@charset is preserved in all resulting sheets', (test) => { 167 | test.plan(3); 168 | const charset = fs.readFileSync('tests/fixtures/charset.css', 'utf8'); 169 | 170 | const name = 'charset-preserved'; 171 | const options = { 172 | maxSelectors: 4 173 | }; 174 | const result = sakugawa(charset, options); 175 | test.equal(result.length, 2, name); 176 | 177 | result.forEach(function (res) { 178 | test.equal(res.indexOf('@charset'), 0); 179 | }); 180 | }); 181 | -------------------------------------------------------------------------------- /wercker.yml: -------------------------------------------------------------------------------- 1 | box: node:16 2 | build: 3 | steps: 4 | - npm-install 5 | - script: 6 | name: nodejs and npm version information 7 | code: npm --versions 8 | - script: 9 | name: ESLint everything! 10 | code: npm run lint 11 | - npm-test 12 | - script: 13 | name: Code coverage with nyc and post to codecov.io 14 | code: npm run coverage 15 | --------------------------------------------------------------------------------