1 | analyze-css
|
2 | ===========
|
3 |
|
4 | [![NPM version](https://badge.fury.io/js/analyze-css.png)](http://badge.fury.io/js/analyze-css)
|
5 | [![Known Vulnerabilities](https://snyk.io/test/github/macbre/analyze-css/badge.svg)](https://snyk.io/test/github/macbre/analyze-css)
|
6 | [![Inline docs](http://inch-ci.org/github/macbre/analyze-css.svg?branch=devel&style=flat-square)](http://inch-ci.org/github/macbre/analyze-css)
|
7 |
|
8 | [![Download stats](https://nodei.co/npm/analyze-css.png?downloads=true&downloadRank=true)](https://nodei.co/npm/analyze-css/)
|
9 |
|
10 | CSS selectors complexity and performance analyzer. analyze-css is built as a set of rules bound to events fired by CSS parser. Each rule can generate metrics and add "offenders" with more detailed information (see Usage section for an example).
|
11 |
|
12 | ## Install
|
13 |
|
14 | analyze-css comes as a "binary" for command-line and as CommonJS module. Run the following to install them globally:
|
15 |
|
16 | ```
|
17 | npm install --global analyze-css
|
18 | ```
|
19 |
|
20 | ## Usage
|
21 |
|
22 | ### Command line tool
|
23 |
|
24 | You can use analyze-css "binary" to analyze local CSS files or remote CSS assets:
|
25 |
|
26 | ```
|
27 | analyze-css --file examples/elecena.css
|
28 |
|
29 | analyze-css --url http://s3.macbre.net/analyze-css/propertyResets.css
|
30 | analyze-css --url https://s3.macbre.net/analyze-css/propertyResets.css --ignore-ssl-errors
|
31 | ```
|
32 |
|
33 | You can provide CSS via stdin as well (notice the dash: ``-``):
|
34 |
|
35 | ```
|
36 | echo ".foo {margin: 0 \!important}" | analyze-css -
|
37 | ```
|
38 |
|
39 | This will emit JSON formatted results on ``stdout``. Use ``--pretty`` (or ``-p`` shortcut) option to make the output readable for human beings.
|
40 |
|
41 | Basic HTTP authentication can be provided through the options `--auth-user` and `--auth-pass`.
|
42 |
|
43 | HTTP proxy (e.g. `http://localhost:8080`) can be provided via:
|
44 |
|
45 | * `--proxy` or `-x` option
|
46 | * `HTTP_PROXY` env variable
|
47 |
|
48 | ### CommonJS module
|
49 |
|
50 | ```js
|
51 | var analyzer = require('analyze-css');
|
52 |
|
53 | new analyzer('.foo {margin: 0 !important}', function(err, results) {
|
54 | console.error(err);
|
55 | console.log(results); // example? see below
|
56 | });
|
57 | ```
|
58 |
|
59 | ```js
|
60 | // options can be provided
|
61 | var opts = {
|
62 | 'noOffenders': true
|
63 | };
|
64 |
|
65 | new analyzer('.foo {margin: 0 !important}', opts, function(err, results) {
|
66 | console.error(err);
|
67 | console.log(results); // example? see below
|
68 | });```
|
69 | ```
|
70 |
|
71 | ### [grunt task](https://www.npmjs.org/package/grunt-contrib-analyze-css)
|
72 |
|
73 | > Created by @DeuxHuitHuit
|
74 |
|
75 | ```
|
76 | npm i grunt-contrib-analyze-css
|
77 | ```
|
78 |
|
79 | It uses configurable threshold and compares the analyze-css result with it.
|
80 |
|
81 | ### Results
|
82 |
|
83 | ```json
|
84 | {
|
85 | "generator": "analyze-css v0.10.2",
|
86 | "metrics": {
|
87 | "base64Length": 11332,
|
88 | "redundantBodySelectors": 0,
|
89 | "redundantChildNodesSelectors": 1,
|
90 | "colors": 106,
|
91 | "comments": 1,
|
92 | "commentsLength": 68,
|
93 | "complexSelectors": 37,
|
94 | "duplicatedSelectors": 7,
|
95 | "duplicatedProperties": 24,
|
96 | "emptyRules": 0,
|
97 | "expressions": 0,
|
98 | "oldIEFixes": 51,
|
99 | "imports": 0,
|
100 | "importants": 3,
|
101 | "mediaQueries": 0,
|
102 | "notMinified": 0,
|
103 | "multiClassesSelectors": 74,
|
104 | "parsingErrors": 0,
|
105 | "oldPropertyPrefixes": 79,
|
106 | "propertyResets": 0,
|
107 | "qualifiedSelectors": 28,
|
108 | "specificityIdAvg": 0.04,
|
109 | "specificityIdTotal": 25,
|
110 | "specificityClassAvg": 1.27,
|
111 | "specificityClassTotal": 904,
|
112 | "specificityTagAvg": 0.79,
|
113 | "specificityTagTotal": 562,
|
114 | "selectors": 712,
|
115 | "selectorLengthAvg": 1.5722460658082975,
|
116 | "selectorsByAttribute": 92,
|
117 | "selectorsByClass": 600,
|
118 | "selectorsById": 25,
|
119 | "selectorsByPseudo": 167,
|
120 | "selectorsByTag": 533,
|
121 | "length": 55173,
|
122 | "rules": 433,
|
123 | "declarations": 1288
|
124 | },
|
125 | "offenders": {
|
126 | "importants": [
|
127 | ".foo {margin: 0 !important}"
|
128 | ]
|
129 | }
|
130 | }
|
131 | ```
|
132 |
|
133 | ## Metrics
|
134 |
|
135 | * **base64Length**: total length of base64-encoded data in CSS source (will warn about base64-encoded data bigger than 4 kB)
|
136 | * **redundantBodySelectors**: number of redundant body selectors (e.g. ``body .foo``, ``section body h2``, but not ``body > h1``)
|
137 | * **redundantChildNodesSelectors**: number of redundant child nodes selectors (e.g. ``ul li``, ``table tr``)
|
138 | * **colors**: number of unique colors used in CSS
|
139 | * **comments**: number of comments in CSS source
|
140 | * **commentsLength**: length of comments content in CSS source
|
141 | * **complexSelectors**: number of complex selectors (consisting of more than three expressions, e.g. ``header ul li .foo``)
|
142 | * **duplicatedSelectors**: number of CSS selectors defined more than once in CSS source
|
143 | * **duplicatedProperties**: number of CSS property definitions duplicated within a selector
|
144 | * **emptyRules**: number of rules with no properties (e.g. ``.foo { }``)
|
145 | * **expressions**: number of rules with CSS expressions (e.g. ``expression( document.body.clientWidth > 600 ? "600px" : "auto" )``)
|
146 | * **oldIEFixes**: number of fixes for old versions of Internet Explorer (e.g. ``* html .foo {}`` and ``.foo { *zoom: 1 }``, [read](http://blogs.msdn.com/b/ie/archive/2005/09/02/460115.aspx) [more](http://www.impressivewebs.com/ie7-ie8-css-hacks/))
|
147 | * **imports** number of ``@import`` rules
|
148 | * **importants**: number of properties with value forced by ``!important``
|
149 | * **mediaQueries**: number of media queries (e.g. ``@media screen and (min-width: 1370px)``)
|
150 | * **notMinified**: set to 1 if the provided CSS is not minified
|
151 | * **multiClassesSelectors**: reports selectors with multiple classes (e.g. ``span.foo.bar``)
|
152 | * **parsingErrors**: number of CSS parsing errors
|
153 | * **oldPropertyPrefixes**: number of properties with no longer needed vendor prefix, powered by data provided by [autoprefixer](https://github.com/ai/autoprefixer) (e.g. ``--moz-border-radius``)
|
154 | * **propertyResets**: number of [accidental property resets](http://css-tricks.com/accidental-css-resets/)
|
155 | * **qualifiedSelectors**: number of [qualified selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Writing_efficient_CSS) (e.g. ``header#nav``, ``.foo#bar``, ``h1.title``)
|
156 | * **specificityIdAvg**: average [specificity](http://css-tricks.com/specifics-on-css-specificity/) for ID
|
157 | * **specificityIdTotal**: total [specificity](http://css-tricks.com/specifics-on-css-specificity/) for ID
|
158 | * **specificityClassAvg**: average [specificity](http://css-tricks.com/specifics-on-css-specificity/) for class, pseudo-class or attribute
|
159 | * **specificityClassTotal**: total [specificity](http://css-tricks.com/specifics-on-css-specificity/) for class, pseudo-class or attribute
|
160 | * **specificityTagAvg**: average [specificity](http://css-tricks.com/specifics-on-css-specificity/) for element
|
161 | * **specificityTagTotal**: total [specificity](http://css-tricks.com/specifics-on-css-specificity/) for element
|
162 | * **selectors**: number of selectors (e.g. ``.foo, .bar { color: red }`` is counted as two selectors - ``.foo`` and ``.bar``)
|
163 | * **selectorLengthAvg**: average length of selector (e.g. for ``.foo .bar, #test div > span { color: red }`` will be set as 2.5)
|
164 | * **selectorsByAttribute**: number of selectors by attribute (e.g. ``.foo[value=bar]``)
|
165 | * **selectorsByClass**: number of selectors by class
|
166 | * **selectorsById**: number of selectors by ID
|
167 | * **selectorsByPseudo**: number of pseudo-selectors (e,g. ``:hover``)
|
168 | * **selectorsByTag**: number of selectors by tag name
|
169 | * **length**: length of CSS source (in bytes)
|
170 | * **rules**: number of rules (e.g. ``.foo, .bar { color: red }`` is counted as one rule)
|
171 | * **declarations**: number of declarations (e.g. ``.foo, .bar { color: red }`` is counted as one declaration - ``color: red``)
|
172 |
|
173 | ## Read more
|
174 |
|
175 | * [Writing Efficient CSS](http://developer.mozilla.org/en/Writing_Efficient_CSS) (by Mozilla)
|
176 | * [Optimize browser rendering](https://developers.google.com/speed/docs/best-practices/rendering) (by Google)
|
177 | * [Profiling CSS for fun and profit. Optimization notes.](http://perfectionkills.com/profiling-css-for-fun-and-profit-optimization-notes/)
|
178 | * [CSS specificity](http://css-tricks.com/specifics-on-css-specificity/)
|
179 | * [CSS Selector Performance has changed! (For the better)](http://calendar.perfplanet.com/2011/css-selector-performance-has-changed-for-the-better/) (by Nicole Sullivan)
|
180 | * [CSS Performance](http://dl.dropboxusercontent.com/u/39519/talks/cssperf/index.html) (by Paul Irish)
|
181 | * [GitHub's CSS Performance](https://speakerdeck.com/jonrohan/githubs-css-performance) (by Joh Rohan)
|
182 |
|
183 | ## Dev hints
|
184 |
|
185 | Running tests and linting the code:
|
186 |
|
187 | ```
|
188 | npm test && npm run-script lint
|
189 | ```
|
190 |
|
191 | Turning on debug mode (i.e. verbose logging to stderr via [debug module](https://npmjs.org/package/debug)):
|
192 |
|
193 | ```
|
194 | DEBUG=analyze-css* analyze-css ...
|
195 | ```
|