- 1. Описание
- 2. Минимизация
- 2.1. Минимизация без изменения структуры
- 2.1.1. Удаление whitespace
- 2.1.2. Удаление концевых ';'
- 2.1.3. Удаление комментариев
- 2.1.4. Удаление неправильных @charset и @import
- 2.1.5. Минимизация цвета
- 2.1.6. Минимизация 0
- 2.1.7. Слияние многострочных строк в однострочные
- 2.1.8. Минимизация font-weight
- 2.2. Минимизация с изменением структуры
- 2.2.1. Слияние блоков с одинаковыми селекторами
- 2.2.2. Слияние блоков с одинаковыми свойствами
- 2.2.3. Удаление перекрываемых свойств
- 2.2.3.1. Удаление перекрываемых shorthand-свойств
- 2.2.4. Удаление повторяющихся селекторов
- 2.2.5. Частичное слияние блоков
- 2.2.6. Частичное разделение блоков
- 2.2.7. Удаление пустых ruleset и at-rule
- 2.2.8. Минимизация margin и padding
- 2.2.9. Специальная минимизация псевдоклассов
- 2.2.9.1. Сохранение группы
- 2.2.9.2. Минимизация общеподдерживаемых псевдоклассов
- 2.2.9.3. Минимизация :before и :after
- 3. Рекомендации
- 3.1. Длина селекторов
- 3.2. Порядок свойств
- 3.3. Расположение схожих блоков
- 3.4. Использование !important
CSSO (CSS Optimizer) является минимизатором CSS, выполняющим как минимизацию без изменения структуры, так и структурную минимизацию с целью получить как можно меньший текст.
Этот документ описывает минимизацию детально. Если вам нужна инструкция по установке, она находится здесь.
Цель минимизации заключается в трансформации исходного CSS в CSS меньшего размера. Наиболее распространёнными стратегиями в достижении этой цели являются:
- минимизация без изменения структуры — удаление необязательных элементов (например,
;
у последнего свойства в блоке), сведение значений к меньшим по размеру (например,0px
к0
) и т.п.; - минимизация с изменением структуры — удаление перекрываемых свойств, полное или частичное слияние блоков.
В ряде случаев символы ряда whitespace (
, \n
, \r
, \t
, \f
) являются необязательными и не влияют на результат применения таблицы стилей.
-
Было:
.test { margin-top: 1em; margin-left : 2em; }
-
Стало:
.test{margin-top:1em;margin-left:2em}
Для большего удобства чтения текст остальных примеров приводится с пробелами (переводом строки и т.п.).
Символ ;
, завершающий перечисление свойств в блоке, является необязательным и не влияет на результат применения таблицы стилей.
-
Было:
.test { margin-top: 1em;; }
-
Стало:
.test { margin-top: 1em }
Комментарии не влияют на результат применения таблицы стилей: [CSS 2.1 / 4.1.9 Comments].
-
Было:
/* comment */ .test /* comment */ { /* comment */ margin-top: /* comment */ 1em; }
-
Стало:
.test { margin-top: 1em }
Единственно верным расположением @charset
является начало текста: [CSS 2.1 / 4.4 CSS style sheet representation].
Однако CSSO позволяет обходиться с этим правилом достаточно вольно, т.к. оставляет первый после whitespace и комментариев @charset
.
Правило @import
на неправильном месте удаляется согласно [CSS 2.1 / 6.3 The @import rule].
-
Было:
/* comment */ @charset 'UTF-8'; @import "test0.css"; @import "test1.css"; @charset 'wrong'; h1 { color: red } @import "wrong";
-
Стало:
@charset 'UTF-8'; @import "test0.css"; @import "test1.css"; h1 { color: red }
Некоторые значения цвета минимизируются согласно [CSS 2.1 / 4.3.6 Colors].
-
Было:
.test { color: yellow; border-color: #c0c0c0; background: #ffffff; border-top-color: #f00; outline-color: rgb(0, 0, 0); }
-
Стало:
.test { color: #ff0; border-color: silver; background: #fff; border-top-color: red; outline-color: #000 }
В ряде случаев числовое значение можно сократить до 0
или же отбросить 0
.
Значения 0%
не сокращаются до 0
, чтобы избежать ошибок вида rgb(100%, 100%, 0)
.
-
Было:
.test { fakeprop: .0 0. 0.0 000 00.00 0px 0.1 0.1em 0.000em 00% 00.00% 010.00 }
-
Стало:
.test { fakeprop: 0 0 0 0 0 0 .1 .1em 0 0% 0% 10 }
Многострочные строки минимизируются согласно [CSS 2.1 / 4.3.7 Strings].
-
Было:
.test[title="abc\ def"] { background: url("foo/\ bar") }
-
Стало:
.test[title="abcdef"] { background: url("foo/bar") }
Значения bold
и normal
свойства font-weight
минимизируются согласно [CSS 2.1 / 15.6 Font boldness: the 'font-weight' property].
-
Было:
.test0 { font-weight: bold } .test1 { font-weight: normal }
-
Стало:
.test0 { font-weight: 700 } .test1 { font-weight: 400 }
В один блок сливаются соседние блоки с одинаковым набором селекторов.
-
Было:
.test0 { margin: 0 } .test1 { border: none } .test1 { background-color: green } .test0 { padding: 0 }
-
Стало:
.test0 { margin: 0 } .test1 { border: none; background-color: green } .test0 { padding: 0 }
В один блок сливаются соседние блоки с одинаковым набором свойств.
-
Было:
.test0 { margin: 0 } .test1 { border: none } .test2 { border: none } .test0 { padding: 0 }
-
Стало:
.test0 { margin: 0 } .test1, .test2 { border: none } .test0 { padding: 0 }
Минимизация удалением перекрываемых свойств основана на том, что внутри блока применяется:
- последнее по порядку свойство, если все свойства не
!important
; - последнее по порядку свойство
!important
.
Это позволяет избавиться от всех игнорируемых браузером свойств.
-
Было:
.test { color: red; margin: 0; line-height: 3cm; color: green; }
-
Стало:
.test { margin: 0; line-height: 3cm; color: green }
Для свойств border
, margin
, padding
, font
и list-style
используется следующий алгоритм удаления: если последним по порядку свойством является более 'широкое' свойство (например, border
), то все предыдущие перекрываемые им свойства удаляются (например, border-top-width
или border-style
).
-
Было:
.test { border-top-color: red; border-color: green }
-
Стало:
.test { border-color:green }
Повторяющиеся селекторы излишни и потому могут быть удалены.
-
Было:
.test, .test { color: red }
-
Стало:
.test { color: red }
Если рядом расположены блоки, один из которых набором свойств полностью входит в другой, возможна следующая минимизация:
- в исходном (наибольшем) блоке удаляется пересекающийся набор свойств;
- селекторы исходного блока копируются в принимающий блок.
Если в символах размер копируемых селекторов меньше размера пересекающегося набора свойств, минимизация происходит.
-
Было:
.test0 { color: red } .test1 { color: red; border: none } .test2 { border: none }
-
Стало:
.test0, .test1 { color: red } .test1, .test2 { border: none }
Если в символах размер копируемых селекторов больше размера пересекающегося набора свойств, минимизация не происходит.
-
Было:
.test0 { color: red } .longlonglong { color: red; border: none } .test1 { border: none }
-
Стало:
.test0 { color: red } .longlonglong { color: red; border: none } .test1 { border: none }
Если рядом расположены блоки, частично пересекающиеся набором свойств, возможна следующая минимизация:
- из обоих блоков выделяется пересекающийся набор свойств;
- между блоками создаётся новый блок с выделенным набором свойств и с селекторами обоих блоков.
Если в символах размер копируемых селекторов меньше размера пересекающегося набора свойств, минимизация происходит.
-
Было:
.test0 { color: red; border: none; margin: 0 } .test1 { color: green; border: none; margin: 0 }
-
Стало:
.test0 { color: red } .test0, .test1 { border: none; margin: 0 } .test1 { color: green }
Если в символах размер копируемых селекторов больше размера пересекающегося набора свойств, минимизация не происходит.
-
Было:
.test0 { color: red; border: none; margin: 0 } .longlonglong { color: green; border: none; margin: 0 }
-
Стало:
.test0 { color: red; border: none; margin: 0 } .longlonglong { color: green; border: none; margin: 0 }
Пустые ruleset и at-rule удаляются.
-
Было:
.test { color: red } .empty {} @font-face {} @media print { .empty {} } .test { border: none }
-
Стало:
.test{color:red;border:none}
Свойства margin
и padding
минимизируются согласно [CSS 2.1 / 8.3 Margin properties] и [CSS 2.1 / 8.4 Padding properties].
-
Было:
.test0 { margin-top: 1em; margin-right: 2em; margin-bottom: 3em; margin-left: 4em; } .test1 { margin: 1 2 3 2 } .test2 { margin: 1 2 1 2 } .test3 { margin: 1 1 1 1 } .test4 { margin: 1 1 1 } .test5 { margin: 1 1 }
-
Стало:
.test0 { margin: 1em 2em 3em 4em } .test1 { margin: 1 2 3 } .test2 { margin: 1 2 } .test3, .test4, .test5 { margin: 1 }
Если в группе селекторов UA обнаружит неподдерживаемый селектор, он, согласно [CSS 3 / Selectors / 5. Groups of selectors], посчитает неподдерживаемой всю группу и не применит стили к перечисленным в ней селекторам. Этим нередко пользуются для разграничения стилей по браузерам. Вот пример метода:
#hackme, x:-moz-any-link { Firefox 2.0 here }
#hackme, x:-moz-any-link, x:default { Firefox 3.0 and newer }
Чтобы сохранить такие блоки, но в то же время минимизировать то, что поддаётся оптимизации, CSSO применяет нижеперечисленные правила. Предполагается, что вместе эти правила составляют компромисс, удовлетворяющий большинство пользователей.
В общем случае (исключения описаны ниже) минимизация удалением перекрываемого селектора не происходит, если группа селекторов включает псевдокласс или псевдоэлемент.
-
Было:
a { property: value0 } a, x:-vendor-class { property: value1 }
-
Стало (структура не изменилась):
a { property: value0 } a, x:-vendor-class { property: value1 }
Если же группы селекторов образуют одинаковую "сигнатуру псевдоклассов" (исключается ситуация, в которой браузер поддерживает одну группу, но не поддерживает другую), минимизация происходит.
-
Было:
a, x:-vendor-class { property: value0 } a, b, x:-vendor-class { property: value1 }
-
Стало:
a, b, x:-vendor-class { property: value1 }
Существуют псевдоклассы и псевдоэлементы, поддерживаемые большинством браузеров: :link
, :visited
, :hover
, :active
, :first-letter
, :first-line
. Для них минимизация происходит в общем порядке без сохранения группы.
-
Было:
a, x:active { color: red } a { color: green }
-
Стало: x:active { color: red }
a { color: green }
Псевдоэлементы :before
и :after
обычно поддерживаются браузерами парно, потому объединение блоков с их участием безопасно.
-
Было:
a, x:before { color: red } a, x:after { color: red }
-
Стало:
a, x:before, x:after { color:red }
Тем не менее, блоки, в которых участвует только один из этих псевдоэлементов, не объединяются:
-
Было:
a { color: red } a, x:after { color: red }
-
Стало:
a { color: red } a, x:after { color: red }
В примере выше можно заметить, что удаление селектора a
из второго блока не повлияло бы на итоговый рендеринг, но в общем случае это опасная минимизация, потому не применяется.
С точки зрения минимизации таблицы стилей можно разделить на две группы: удобные и неудобные. Разница даже в один символ может превратить вполне сокращаемый исходный текст в минимально обрабатываемый.
Если вы хотите помочь минимизатору хорошо выполнить работу, следуйте рекомендациям.
Чем короче селектор (whitespace не учитываются), тем больше вероятность удачного группирования.
Придерживайтесь во всём CSS одного порядка, в котором перечисляются свойства, так вам не потребуется защита от смены порядка. Соответственно, меньше вероятность допустить ошибку и помешать минимизатору излишним управлением.
Располагайте блоки со схожим набором свойств как можно ближе друг к другу.
Плохо:
-
Было:
.test0 { color: red } .test1 { color: green } .test2 { color: red }
-
Стало (53 символа):
.test0{color:red}.test1{color:green}.test2{color:red}
Хорошо:
-
Было:
.test1 { color: green } .test0 { color: red } .test2 { color: red }
-
Стало (43 символа):
.test1{color:green}.test0,.test2{color:red}
Очевидно, !important
оказывает серьёзное влияние на минимизацию, особенно заметно это может отразиться на минимизации margin
и padding
, потому им лучше не злоупотреблять.
Плохо:
-
Было:
.test { margin-left: 2px !important; margin: 1px; }
-
Стало (43 символа):
.test{margin-left:2px!important;margin:1px}
Хорошо:
-
Было:
.test { margin-left: 2px; margin: 1px; }
-
Стало (17 символов):
.test{margin:1px}