Skip to content

Commit 72f63f6

Browse files
authored
Merge pull request hail2u#44 from hail2u/notes
Clarify CSS MQPacker mechanism in README
2 parents 36a03de + cd3c4c7 commit 72f63f6

File tree

1 file changed

+221
-46
lines changed

1 file changed

+221
-46
lines changed

README.md

Lines changed: 221 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,48 +7,47 @@ Pack same CSS media query rules into one using PostCSS
77
SYNOPSIS
88
--------
99

10-
A CSS file processed with a CSS pre-processor may have same queries that can
11-
merge:
10+
A well componentized CSS file may have same media queries that can merge:
1211

1312
```css
14-
.foo::before {
15-
content: "foo on small";
13+
.foo {
14+
width: 240px;
1615
}
1716

18-
@media screen and (min-width: 769px) {
19-
.foo::before {
20-
content: "foo on medium";
17+
@media screen and (min-width: 768px) {
18+
.foo {
19+
width: 576px;
2120
}
2221
}
2322

24-
.bar::before {
25-
content: "bar on small";
23+
.bar {
24+
width: 160px;
2625
}
2726

28-
@media screen and (min-width: 769px) {
29-
.bar::before {
30-
content: "bar on medium";
27+
@media screen and (min-width: 768px) {
28+
.bar {
29+
width: 384px;
3130
}
3231
}
3332
```
3433

35-
This PostCSS plugin packs exactly same queries (and optionally sorts) like this:
34+
This PostCSS plugin packs exactly same media queries:
3635

3736
```css
38-
.foo::before {
39-
content: "foo on small";
37+
.foo {
38+
width: 240px;
4039
}
4140

42-
.bar::before {
43-
content: "bar on small";
41+
.bar {
42+
width: 160px;
4443
}
4544

46-
@media screen and (min-width: 769px) {
47-
.foo::before {
48-
content: "foo on medium";
45+
@media screen and (min-width: 768px) {
46+
.foo {
47+
width: 576px;
4948
}
50-
.bar::before {
51-
content: "bar on medium";
49+
.bar {
50+
width: 384px;
5251
}
5352
}
5453
```
@@ -70,40 +69,40 @@ Of course, this package can be used as PostCSS plugin:
7069

7170
"use strict";
7271

73-
var fs = require("fs");
74-
var postcss = require("postcss");
72+
const fs = require("fs");
73+
cosnt postcss = require("postcss");
7574

76-
var css = fs.readFileSync("from.css", "utf8");
7775
postcss([
7876
require("autoprefixer-core")(),
7977
require("css-mqpacker")()
80-
]).process(css).then(function (result) {
78+
]).process(fs.readFileSync("from.css", "utf8")).then(function (result) {
8179
console.log(result.css);
8280
});
8381
```
8482

83+
It is a recommended way to use this tool.
84+
8585

8686
### As standard Node.js package
8787

88-
Read `from.css`, process its content, and output processed CSS to STDOUT.
88+
This package is also a Node.js module. For exmaple, you can read `from.css`,
89+
process its content, and output processed CSS to STDOUT:
8990

9091
```javascript
9192
#!/usr/bin/env node
9293

9394
"use strict";
9495

95-
var fs = require("fs");
96-
var mqpacker = require("css-mqpacker");
96+
const fs = require("fs");
97+
const mqpacker = require("css-mqpacker");
9798

98-
var original = fs.readFileSync("from.css", "utf8");
99-
var processed = mqpacker.pack(original, {
99+
cosole.log(mqpacker.pack(fs.readFileSync("from.css", "utf8"), {
100100
from: "from.css",
101101
map: {
102102
inline: false
103103
},
104104
to: "to.css"
105-
});
106-
console.log(processed.css);
105+
}).css);
107106
```
108107

109108

@@ -134,14 +133,18 @@ format instead of Node.js stack trace.
134133

135134
The `--sort` option does not currently support a custom function.
136135

136+
If you install this package in global, CLI will be available somewhere in the
137+
`$PATH`.
138+
137139

138140
OPTIONS
139141
-------
140142

141143
### sort
142144

143-
By default, CSS MQPacker pack and order media queries as they are defined. If
144-
you want to sort queries automatically, pass `sort: true` to this module.
145+
By default, CSS MQPacker pack and order media queries as they are defined ([the
146+
“first win” algorithm][1]). If you want to sort media queries automatically,
147+
pass `sort: true` to this module.
145148

146149
```javascript
147150
postcss([
@@ -165,10 +168,10 @@ postcss([
165168
]).process(css);
166169
```
167170

168-
In this example, all your queries will sort by A-Z order.
171+
In this example, all your media queries will sort by A-Z order.
169172

170-
This sorting function directly pass to `Array#sort()` method of an array of all
171-
your queries.
173+
This sorting function is directly passed to `Array#sort()` method of an array of
174+
all your media queries.
172175

173176

174177
API
@@ -180,17 +183,16 @@ Packs media queries in `css`.
180183

181184
The second argument is optional. The `options` are:
182185

183-
- [options][1] mentioned above
184-
- the second argument of [PostCSS’s `process()` method][2]
186+
- [options][2] mentioned above
187+
- the second argument of [PostCSS’s `process()` method][3]
185188

186189
You can specify both at the same time.
187190

188191
```javascript
189-
var fs = require("fs");
190-
var mqpacker = require("css-mqpacker");
192+
cosnt fs = require("fs");
193+
const mqpacker = require("css-mqpacker");
191194

192-
var css = fs.readFileSync("from.css", "utf8");
193-
var result = mqpacker.pack(css, {
195+
const result = mqpacker.pack(fs.readFileSync("from.css", "utf8"), {
194196
from: "from.css",
195197
map: {
196198
inline: false
@@ -203,11 +205,184 @@ fs.writeFileSync("to.css.map", result.map);
203205
```
204206

205207

208+
NOTES
209+
-----
210+
211+
With CSS MQPacker, the processed CSS is always valid CSS, but you and your
212+
website user will get unexpected results. This section explains how CSS MQPacker
213+
works and what you should keep in mind.
214+
215+
216+
### CSS Cascading Order
217+
218+
CSS MQPacker changes rulesets’ order. This means the processed CSS will have an
219+
unexpected cascading order. For example:
220+
221+
```css
222+
@media (min-width: 640px) {
223+
.foo {
224+
width: 300px;
225+
}
226+
}
227+
228+
.foo {
229+
width: 400px;
230+
}
231+
```
232+
233+
Becomes:
234+
235+
```css
236+
.foo {
237+
width: 400px;
238+
}
239+
240+
@media (min-width: 640px) {
241+
.foo {
242+
width: 300px;
243+
}
244+
}
245+
```
246+
247+
`.foo` is always `400px` with original CSS. With processed CSS, however, `.foo`
248+
is `300px` if viewport is wider than `640px`.
249+
250+
This does not occur on small project. However, this could occur frequently on
251+
large project. For example, if you want to override a CSS framework (like
252+
Bootstrap) component declaration, your whole CSS code will be something similar
253+
to above example. To avoid this problem, you should pack only CSS you write, and
254+
then concaenate with a CSS framework.
255+
256+
257+
### The “First Win” Algorithm
258+
259+
CSS MQPacker is implemented with the “first win” algorithm. This means:
260+
261+
```css
262+
.foo {
263+
width: 10px;
264+
}
265+
266+
@media (min-width: 640px) {
267+
.foo {
268+
width: 150px;
269+
}
270+
}
271+
272+
.bar {
273+
width: 20px;
274+
}
275+
276+
@media (min-width: 320px) {
277+
.bar {
278+
width: 200px;
279+
}
280+
}
281+
282+
@media (min-width: 640px) {
283+
.bar {
284+
width: 300px;
285+
}
286+
}
287+
```
288+
289+
Becomes:
290+
291+
```css
292+
.foo {
293+
width: 10px;
294+
}
295+
296+
.bar {
297+
width: 20px;
298+
}
299+
300+
@media (min-width: 640px) {
301+
.foo {
302+
width: 150px;
303+
}
304+
.bar {
305+
width: 300px;
306+
}
307+
}
308+
309+
@media (min-width: 320px) {
310+
.bar {
311+
width: 200px;
312+
}
313+
}
314+
```
315+
316+
This breaks cascading order of `.bar`, and `.bar` will be displayed in `200px`
317+
instead of `300px` even if a viewport wider than `640px`.
318+
319+
I suggest defining a query order on top of your CSS:
320+
321+
```css
322+
@media (min-width: 320px) { /* Wider than 320px */ }
323+
@media (min-width: 640px) { /* Wider than 640px */ }
324+
```
325+
326+
If you use simple `min-width` queries only, [the `sort` option][4] can help.
327+
328+
329+
### Multiple Classes
330+
331+
CSS MQPacker works only with CSS. This may break CSS applying order to an
332+
elements that have multiple classes. For example:
333+
334+
```css
335+
@media (min-width: 320px) {
336+
.foo {
337+
width: 100px;
338+
}
339+
}
340+
341+
@media (min-width: 640px) {
342+
.bar {
343+
width: 200px;
344+
}
345+
}
346+
347+
@media (min-width: 320px) {
348+
.baz {
349+
width: 300px;
350+
}
351+
}
352+
```
353+
354+
Becomes:
355+
356+
```css
357+
@media (min-width: 320px) {
358+
.foo {
359+
width: 100px;
360+
}
361+
.baz {
362+
width: 300px;
363+
}
364+
}
365+
366+
@media (min-width: 640px) {
367+
.bar {
368+
width: 200px;
369+
}
370+
}
371+
```
372+
373+
The result looks good. However, if an HTML element has `class="bar baz"` and
374+
viewport width larger than `640px`, that element `width` incorrectly set to
375+
`200px` instead of `300px`. This problem cannot be resolved only with CSS, so be
376+
careful!
377+
378+
206379
LICENSE
207380
-------
208381

209382
MIT: http://hail2u.mit-license.org/2014
210383

211384

212-
[1]: #options
213-
[2]: https://github.com/postcss/postcss#source-map
385+
[1]: #the-first-win-algorithm
386+
[2]: #options
387+
[3]: http://api.postcss.org/global.html#processOptions
388+
[4]: #sort

0 commit comments

Comments
 (0)