CSSO – compress CSS (english version)
-
Upload
roman-dvornov -
Category
Technology
-
view
597 -
download
7
Transcript of CSSO – compress CSS (english version)
CSSO — compress CSS
Roman Dvornov Avito
Minsk 2016
Working at Avito
Building SPA
Author of basis.js
Maintainer of CSSO
3
Don't expect happy end
CSS-minifiers aren't needed!
It's a joke… or maybe notCSS-minifiers aren't needed!
5
Fast browsers
Heavy sites
5
Fast browsers
Heavy sites
a lot of CSS – compression needed
What tool to choose?
7
cssnanocsso clean-cssYUI Compressor fork
ycssmin
Heroes of the day
7
cssnanocsso clean-cssYUI Compressor fork
ycssmin
Heroes of the day
7
cssnanocsso clean-cssYUI Compressor fork
ycssmin
Heroes of the day
7
cssnanocsso clean-cssYUI Compressor fork
ycssmin
Heroes of the day
7
cssnanocsso clean-cssYUI Compressor fork
ycssmin
Heroes of the day
7
cssnanocsso clean-cssYUI Compressor fork
ycssmin
Heroes of the day
7
cssnanocsso clean-cssYUI Compressor fork
ycssmin
Heroes of the day
7
cssnanocsso clean-cssYUI Compressor fork
ycssmin
Heroes of the day
8
There are much more minifiers but not so famous or
not in active developing
Let's compare
10
clean-css 3.4.9 cssnano 3.5.2 csso 2.0.0
bootstrap.css147 427 bytes
118 186273 ms
117 4401 813 ms
117 756169 ms
foundation.css200 341 bytes
142 667389 ms
145 0301 983 ms
144 262222 ms
normalize.css7 707 bytes
17925 ms
182417 ms
1 8314 ms
reset.css1 092 bytes
758 3 ms
77313 ms
7473 ms
goalsmashers.github.io/css-minification-benchmark/
It looks like…
Libraries are written well, real CSS is not
12
13
clean-css 3.4.9 cssnano 3.5.2 csso 2.0.0
ActiAgent.ru602 233 bytes (5 month ago)
430 2401 077 ms
439 02423 270 ms
435 588531 ms
ActiAgent.ru822 021 bytes (now)
587 9061 705 ms
604 50348 550 ms
595 834616 ms
gzip compression factor is 8 (~72Kb) That means the result can be improved!
Our numbers
Minification
Every minifier works the same way
Basic minification
• Deletion
• Replacement
• Structural optimization
16
You may think that CSS minification is all about
W3C specifications
17
In fact sh*t happens all the time
That's why
• Specs are changing
• Various browser support of CSS
• Browser's bugs
• CSS hacks
19
Most important
Minification shouldn't break or repair the CSS
20
Deletion
What to delete• Whitespaces and comments (most part of saving)
• Rules with wrong selectors
• Empty rules
• Wrong declarations
• Malposed @import, @charset
• …
22
Always respect specifications
23
24
calc(4 * 2em - 10% / 3)Original CSS
Wrong
calc(4*2em-10%/3)
Correct
calc(4*2em - 10%/3)
Whitespace deletion
More examples• Units for zero dimensions0px ! 0
• Quotes[attr="name"] ! [attr=name] url('image.png') ! url(image.png)
• …
25
But it's not so simple• 0px ! 0
correct
26
But it's not so simple• 0px ! 0
correct• 0deg ! 0
wrong, not a length unit
26
But it's not so simple• 0px ! 0
correct• 0deg ! 0
wrong, not a length unit• flex: 1 0 0px ! flex: 1 0 0
wrong, doesn't work as expected in IE
26
Replacement
Replace with shorter forms
28
Most interesting: colour• hsl ! rgb, hsla ! rgba
• rgb(100%, 0, 0) ! rgb(255, 0, 0)
• rgba(a, b, c, 1) ! rgb(a, b, c)
• normalize: rgb(500, -100, 0) ! rgb(255, 0, 0)
• rgb(255, 0, 0) ! #ff0000
• #aabbcc ! #abc
• #ff0000 ! red, darkslateblue ! #483d8b29
More examples• Number normalization: 0.00 ! 0 or 0.123 ! .123
• Special values for some properties
• font-weight:bold ! font-weight:700
• background:none ! background:0 0
• from ! 0%, 100% ! to for @keyframes
• …
30
Isn't effective actually
Structural optimization
Merging and moving declarations and rules
33
The most complicated and expensive optimization
35
.foo { color: red; color: green;}
.foo { color: green;}
Declaration deletion
color: red has never to be used by browser – can be deleted
Let's check Are you a proper minifier or not? ;)
36
37
.foo { color: red; color: rgba(…);}
.foo { color: rgba(…);}
Deletion of declarationsCorrect?
37
.foo { color: red; color: rgba(…);}
.foo { color: rgba(…);} Wrong
Old browsers don't support rgba()
Deletion of declarationsCorrect?
38
.foo { color: red;}.bar { color: green;}.qux { color: red;}
.foo, .qux { color: red;}.bar { color: green;}
RegroupingCorrect?
38
.foo { color: red;}.bar { color: green;}.qux { color: red;}
.foo, .qux { color: red;}.bar { color: green;}
Wrong
Different results, e.g.<div class="bar qux">
RegroupingCorrect?
39
span { color: red;}div { color: green;}ul { color: red;}
span, ul { color: red;}div { color: green;}
RegroupingCorrect?
39
span { color: red;}div { color: green;}ul { color: red;}
span, ul { color: red;}div { color: green;}
Correct, elements have a single name
RegroupingCorrect?
40
.foo { color: red;}span { color: green;}.bar { color: red;}
.foo, .bar { color: red;}span { color: green;}
RegroupingCorrect?
40
.foo { color: red;}span { color: green;}.bar { color: red;}
.foo, .bar { color: red;}span { color: green;}
Correct,different specificity –order doesn't matter
RegroupingCorrect?
41
.foo { color: red;}.bar:not(.baz) { color: red;}
.foo,
.bar:not(.baz) { color: red;}
RegroupingCorrect?
41
.foo { color: red;}.bar:not(.baz) { color: red;}
.foo,
.bar:not(.baz) { color: red;}
RegroupingCorrect?
Old browsers don't support :not()
Wrong
42
.foo { color: red; width: 100px;}.bar { color: green; width: 100px;}
.foo, .bar { width: 100px;}.foo { color: red;}.bar { color: green;}
Moving common parts aside
Moving direction matters
43
44
.foo { color: red;}.bar { color: red; color: rgba(..);}
.foo, .bar { color: red;}.bar { color: rgba(..);}
Moving common parts aside
In this case only moving up is correct
45
.foo { color: rgba(..);}.bar { color: red; color: rgba(..);}
.bar { color: red;}.foo, .bar { color: rgba(..);}
Moving common parts aside
In this case only moving down is correct
Too many things minifier should respect…
46
Basic optimization summary• Common approaches
• Usually whitespace deletion is most effective
• Many hacks and edge cases
• Every minifier has bugs
47
Advanced optimizations
Usage data
Usage data
50
.foo { color: red;}.bar { color: green;}.qux { color: red;}
.foo, .qux { color: red;}.bar { color: green;}
This transformation isn't safe, since we don't know how CSS is used in markup
Example
But what if we knew?
51
Filtering
53
{ "classes": ["foo", "bar"], "tags": ["ul", "li"]}
.foo { color: red }div.bar { color: green }ul li, ol li { color: blue }
usage.json
CSS
+ .foo { color: red }ul li { color: blue }
Result
Scopes
55
.module1-foo { background: red; }
.module1-bar { font-size: 1.5em; background: yellow; }
.module2-baz { background: red; }
.module2-qux { font-size: 1.5em; background: yellow; width: 50px; }
Rules with .module1-foo and .module2-baz can't be merged,
since .module1-bar is between them
56
.module1-foo { background: red; }
.module1-bar { font-size: 1.5em; background: yellow; }
.module2-baz { background: red; }
.module2-qux { font-size: 1.5em; background: yellow; width: 50px; }
Rules merge is safe only if we sure that class names are never applied to a single element
Usage data
57
{ "scopes": [ ["module1-foo", "module1-bar"], ["module2-baz", "module2-qux"] ]}
With this JSON we explain to optimizer thatmodule1-* and module2-* class names are never applied to a single element
The basic minification result (157 bytes)
58
.module1-foo,.module2-baz{background:red}
.module1-bar,.module2-qux{font-size:1.5em;background:#ff0}
.module2-qux{width:50px}
34 bytes extra saving
.module1-foo{background:red}.module1-bar{font-size:1.5em;background:#ff0}.module2-baz{background:red}.module2-qux{font-size:1.5em;background:#ff0;width:50px}
The result with usage data (123 bytes)
59
Feature is already available in CSSO!
Profit for our project
• 823 Kb Original CSS
• 596 Kb Basic optimization
• 437 Kb Optimization with usage data
60
159 Kb extra saving (26%)
How to generate usage data?
61
There is no universal solution – it depends on the technology stack
It is expected such tools will be created soon
Rename
Rename
63
.foo { color: red }
.foo.bar { color: green }
.a { color: red }
.a.b { color: green }
{ "foo": "a", "bar": "b"}
Rename map
Result
CSS+
64
• 823 Kb Orignal CSS
• 596 Kb Basic optimization
• 385 Kb Rename (currently outside CSSO)
211 Kb of extra saving (35%)
Profit for our project
65
364Kb of extra saving (61%)
All together
• 823 Kb Original CSS
• 596 Kb Basic optimization
• 232 Kb Rename + Usage data
Should it be a part of minifier?
66
Yep, because it leads to a new optimization
67
.foo,
.bar { color: red;}.foo:hover,.bar:hover { color: green}
.a { color: red }
.a:hover { color: green }
{ "foo": "a", "bar": "a"}
Rename map
ResultCSS
+
The single new name for old two names – reduce selector count
Nobody writes this sort of CSS…
68
69
.foo { color: red;}.foo:hover { color: green}
.bar { color: red;}.bar:hover { color: green}
ResultCSS + usage data.foo,.bar { color: red;}.foo:hover,.bar:hover { color: green}
In development – coming soon in CSSO
71
• ~10 Kb of extra saving (~3-4%)
• 1431 of 6904 selectors were deleted
Selector count decreased by ~20%
Profit for our projectquick and dirty numbers
72
To compress or not to compress?
What is the effect of minification?
73
74
Network
Paint
Parse Stylesheet
Recalculate Style
Layout
How CSS to became an image
75
Network
Paint
Parse Stylesheet
Recalculate Style
Layout
Characteristics of CSS that affect performance
Quantitative characteristics matters (size, number of selectors etc.)
Qualitative characteristics matters (complexity of layout and effects)
76
Network
Paint
Parse Stylesheet
Recalculate Style
Layout
Automation of enhancement
Compression can give a positive effect
Currently, have no ideas how to automate optimizations
77
Network
Paint
Parse Stylesheet
Recalculate Style
Layout
Network
Solution: gzip, SDCH …
It matters for cold page load only
78
Network
Paint
Parse Stylesheet
Recalculate Style
Layout
Parse Stylesheet
Solution: use a minifier
Performs every time on page load
Less text – less to parse
Original CSS 823 Kb – 35ms Basic optimisations 596 Kb – 29ms
Rename 385 Kb – 24ms Rename + usage data 232 Kb – 22ms
79
Quick and dirty testsVarious level of compression and its influence on Parse Stylesheet
Size is reduced by ~4 times, time by ~40%
(Chrome on MacBook Air)
Win10 Desktop 19ms → 11ms Nexus 5X 68ms → 44ms
Samsung Galaxy Note 2 158ms → 108ms 80
Quick and dirty tests
On other devices there were more encouraging numbers
CSS 316Kb 215Kb (-39.5%)+ usage data
81
Network
Paint
Parse Stylesheet
Recalculate Style
Layout
Recalculate Style
Solution: rename etc.
Performs every time on page load and on any DOM mutation
We've hypotheses only, more details when feature will be shipped in CSSO ;)
To compress or not to compress?
82
To compress or not to compress?
82
Yes!But it's still a subject for research
CSSO reborn
What was changed• 10+ times faster
• 8+ times less memory consumption
• Fixed most of bugs
• Better code base and API
• More downloads and stars on GitHub ;)84
85
1 300 000+ downloads per month9x since October 2015
Com
pres
sion
tim
e (6
00Kb
CSS
file
)
500 ms
1 000 ms
1 500 ms
2 000 ms
2 500 ms
3 000 ms
3 500 ms
4 000 ms
4 500 ms
5 000 ms
5 500 ms
6 000 ms
CSSO version
1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0
1 050 msclean-css
Performance changes
csso500 ms
cssnano23 250 ms
postcss-csso
87
Plugin for PostCSS
As fast as CSSO alone
Under the hood the plugin converts PostCSS AST into CSSO format, optimises it and converts back
github.com/lahmatiy/postcss-csso
New features• Source Maps
• Usage data
• Support for new parts of CSS
• User friendly error messages
• Support for stdin
• New AST format
88
Plans
Main goal is to build the best CSS optimizer
Coming soon• New algorithms and optimizations
• Browser support modes
• Property families and declaration sorting
• Name normalization and renaming
• Shorthand properties structure recognition
• And more…91
Conclusion
Like CSS, read specs
94 Try CSSO :)
95
All new around CSSO – @cssoptimizer
Roman Dvornov @rdvornov
Any questions?
github.com/css/csso