CSSO

Ребята из симферопольского «Яндекса» сказали новое слово в оптимизации CSS — CSSO. Оптимизатор интересен тем, что умеет минимизировать с изменением структуры — то есть удалять перекрываемые свойства, производить слияние блоков с одинаковыми селекторами и тому подобное.

Сергей Крыжановский, который занимается программированием CSSO, в своём блоге хорошо описал отличия CSSO от YUI Compressor, CSSTidy и им подобных.

Например, CSSO умеет вот такое:
/* до CSSO */
.a {
    color: red;
    border: 0;
}

.b {
    color: red;
}

/* после CSSO */
.a{border:0}.a,.b{color:red}
Меня несказанно печалит, что оптимизатор написан на JavaScript, потому что хостинг с серверным JS найти крайне проблематично, но зато оптимизацию в действии можно попробовать прямо в браузере.
28 апреля 2011 23:22

parpalak (written.ru)
28 апреля 2011, 23:58

А я правильно понимаю, что такая оптимизация CSS, как в примере выше, несколько противоречит рекомендациям по повышению скорости рендеринга в браузерах (из-за того, что .a встречается два раза):
http://code.google.com/speed/page-speed/docs/rendering.html#UseEfficientCSSSelectors

Или браузеры при парсинге CSS догадываются объединять эти две группы правил для .a в одну?

bolk (bolknote.ru)
29 апреля 2011, 00:26, ответ предназначен parpalak (written.ru):

Или браузеры при парсинге CSS догадываются объединять эти две группы правил для .a в одну?
Честно сказать, не представляю как может быть иначе.

greli (greli.livejournal.com)
29 апреля 2011, 01:09, ответ предназначен parpalak (written.ru):

Проигрышь в скорости рендеринга, если и будут, то доли микросекунды, а выигрыш благодаря уменьшению размера куда более заметен. Сетевые задержки могут составлять секунды, а процессор обработает этот случай куда быстрее, чем будет передаваться лишние байты.

skryzhanovsky (инкогнито)
29 апреля 2011, 02:04, ответ предназначен bolk (bolknote.ru):

При написании CSSO изначально закладывался потенциал портирования на другие языки. JS там очень простой, магия [почти] не применяется. Фактически, для каждой функции примерял то, как она будет выглядеть на Java, C++, Python и т.д. Вроде проблем не будет. Когда релиз выйдет на 2.0.0 (сейчас всё-таки слишком много TODO), можно будет плавно портировать.

skryzhanovsky (инкогнито)
29 апреля 2011, 02:20, ответ предназначен parpalak (written.ru):

Такие потери — больше теория, чем практика.
1. Парсеры браузеров тратят на разбор CSS миллисекунды, это копейки в сравнении со всем остальным. Плюсминус копейка — даже толком не измерить, т.к. войдёт в погрешность.
2. Результат разбора уходит во внутренние структуры, которые гораздо, гораздо сложнее того, как выглядит текст CSS. В одном браузере группы объединятся, в другом размножатся (утрирую, но). Внутри свои алгоритмы и свои правила, пытаться учитывать их смысла нет.

Orcinus Orca (orcinus.ru)
29 апреля 2011, 07:34

А я всегда использовал перечисление, как здесь используется. Никаких тормозов не замечал. И вроде все браузеры на это адекватно смотрят.

bolk (bolknote.ru)
29 апреля 2011, 09:15, ответ предназначен skryzhanovsky

При написании CSSO изначально закладывался потенциал портирования на другие языки. JS там очень простой, магия [почти] не применяется.
Да, я смотрел, код правда простой.

Кстати, если ты сразу смотрел на другие языки, тогда можно было написать какой-нибудь простой интерпретатор инструкций (DSL), тогда инструкции можно было бы обновлять сразу на всех языках.

bolk (bolknote.ru)
29 апреля 2011, 09:16, ответ предназначен skryzhanovsky

skryzhanovsky
Можно использовать «skryzhanovsky.ya.ru» вместо имени, тогда сразу по OpenID будет.

Orcinus Orca (orcinus.ru)
29 апреля 2011, 10:08, ответ предназначен bolk (bolknote.ru):

А у меня заработал OpenID на твоем блоге.

bolk (bolknote.ru)
29 апреля 2011, 10:34, ответ предназначен Orcinus Orca (orcinus.ru):

Не работал раньше?

Сергей Крыжановский (skryzhanovsky.ya.ru)
29 апреля 2011, 10:39, ответ предназначен bolk (bolknote.ru):

А разверни мысль про DSL, а то я сейчас нафантазировал вплоть до первичной компиляции CSS в CSS-байткод. :)

Orcinus Orca (orcinus.ru)
29 апреля 2011, 10:45, ответ предназначен bolk (bolknote.ru):

Да, я тебе по этому поводу писал. А тут, смотрю сегодня - заработал.

boltai-shaltai (инкогнито)
29 апреля 2011, 13:10

Мне сейчас кажется, что в режиме структурной оптимизации должны только выдаваться предупреждения, но код трогать не надо. Исходный код на основе выданных ворнингов должен реструктурировать сам верстальщик, если захочет. Иначе такой исходный CSS будет просто "плохим" кодом, не готовым для продакшена - непродуманным, избыточным, плохо струтурированным. Зачем интеллектуальную (не очень алгоритмизируемую) работу по структурированию отдавать оптимизатору?

А часто повторяемость намеренно добавляется для удобочитаемости. И я бы её просто оставлял в покое, не выкусывал - процент в хорошем коде совсем невелик и погоды не сделает. Но это умозрительное имхо, конечно. Надо просто попробовать на "хорошем" коде )) Может, кто-то пробовал уже?

Но однозначно тулза пригодится для "плохого"/чужого кода. Иногда с первого взгляда видно - каша! покоцать её не глядя.

bolk (bolknote.ru)
29 апреля 2011, 13:41, ответ предназначен Сергей Крыжановский (skryzhanovsky.ya.ru):

А разверни мысль про DSL, а то я сейчас нафантазировал вплоть до первичной компиляции CSS в CSS-байткод. :)
Не, я не про это. Придумать язык, на котором можно было бы выражать конструкции оптимизации. Что-то в сторону БНФ, плюс некий язык для правил изменения кода.

Сергей Крыжановский (skryzhanovsky.ya.ru)
29 апреля 2011, 14:25, ответ предназначен boltai-shaltai

Дело в том, что CSS'ы объёмом в 50..70Kb — уже не редкость. Там сотни селекторов и тысячи свойств. В итоге получим под сотню предупреждений и рекомендаций, а разработчик это будет руками разводить? Дык уже не разводят, потому с середины прошлого десятилетия минимизаторы и пошли толпой.
Удобочитаемость — результат минимизации не предназначен для чтения человеком. Это сродни компиляции.

Сергей Крыжановский (skryzhanovsky.ya.ru)
29 апреля 2011, 14:29, ответ предназначен bolk (bolknote.ru):

А, понятно. Я зачатки такого уже сделал, правда, пока лишь в запретительных целях ("не удаляй свойство", "не меняй порядок"). Посмотрим, будет ли удобно и в каком виде такой почти-DSL в CSS внедрять.

boltai-shaltai (инкогнито)
29 апреля 2011, 14:36, ответ предназначен Сергей Крыжановский (skryzhanovsky.ya.ru):

Дык уже не разводят
Вы тоже? Не верю. Любой _нормальный_ кодер, которому к тому же не капают на мозги и не гонят на скорость, всё же стремится написать стройный код.
Это сродни компиляции.
Нну.. вот и плохо, что так пишут. Разгребать такой код весьма противно. Я не хотел бы оставлять за собой такую пакость.

bolk (bolknote.ru)
29 апреля 2011, 14:43, ответ предназначен Сергей Крыжановский (skryzhanovsky.ya.ru):

А, понятно. Я зачатки такого уже сделал, правда, пока лишь в запретительных целях ("не удаляй свойство", "не меняй порядок").
Не-не, ты другое говоришь. Ты сейчас про запретительные инструкции в CSS, а я про то, чтобы парсер и оптимизатор делать не на JS, а на DSL, а интерпретатор DSL уже делать на нужном языке.

Сергей Крыжановский (skryzhanovsky.ya.ru)
29 апреля 2011, 15:04, ответ предназначен boltai-shaltai

Вы тоже? Не верю. Любой _нормальный_ кодер, которому к тому же не капают на мозги и не гонят на скорость, всё же стремится написать стройный код.
Кажется, упускаете два распространённых случая:
1. Генерация CSS. Каждый раз руками допиливать за каким-нибудь не очень чисто работающим роботом — то ещё удовольствие.
2. Собираемый CSS. Как ни старайся, а при склейке сотни блоков окажется избыточность. Каждый раз после сборки её устранять — тоже серьёзная трата времени.
Нну.. вот и плохо, что так пишут. Разгребать такой код весьма противно. Я не хотел бы оставлять за собой такую пакость.
Повторю: CSS в 50..70Kb. :) Разработчик может быть сколь угодно гениальным, но удержать в голове контекст такого объёма и постоянно в голове же оптимизировать... Ну, возможно, да. На это будет уходить половина рабочего времени.

Сергей Крыжановский (skryzhanovsky.ya.ru)
29 апреля 2011, 15:16, ответ предназначен bolk (bolknote.ru):

Теперь понятнее. :) Такой вариант рассматривал, но отклонил. Я хочу позже написать немножко записей о минимизации, там же опишу причины, по которым CSSO на JS и сделан так, как сделан. Сейчас бегло получится, потому плохо. Но поверь, причины решений есть. :)

boltai-shaltai (инкогнито)
29 апреля 2011, 15:55, ответ предназначен Сергей Крыжановский (skryzhanovsky.ya.ru):

Про генерируемый код согласен.
Про собираемый - не совсем понятно. Собираются же фрагменты, описывающие независимые элементы? Откуда там повторы, если классы разные?
удержать в голове контекст такого объёма
Под "хорошим" кодом я имел в виду такой, который как раз не надо держать в голове целиком. Те же "независимые блоки" вполне снимают головную боль, ограничивая контекст.

Сергей Крыжановский (skryzhanovsky.ya.ru)
29 апреля 2011, 16:06, ответ предназначен boltai-shaltai

Классы разные, свойства и значения свойств одинаковые. Упростим до немного детского примера: .myclass0 { color: red } .myclass1 { color: red }.
В худшем случае после сборки итогового CSS из запчастей мы получим простыню из такого перечисления классов.
Думается, работу по превращению такой простыни в .myclass0,.myclass1 { color: red } лучше переложить на плечи роботов.

boltai-shaltai (инкогнито)
29 апреля 2011, 16:24, ответ предназначен Сергей Крыжановский (skryzhanovsky.ya.ru):

Нда, я тут проклинил и говорил больше о тупом копипастерстве, о явной избыточности. А такая группировка как самоцель как-то вылетела из головы.

А она что, реально экономит объём? Селекторы с именами классов и иерархией бывают довольно объёмные, и их "размножение" при группировке по свойствам может раздуть объём. Я понимаю, что вы там всё взвешиваете, на то и оптимизация. Но на реальном-то коде что происходит, есть у вас оценки?

Сергей Крыжановский (skryzhanovsky.ya.ru)
29 апреля 2011, 16:36, ответ предназначен boltai-shaltai

Очень зависит от того, какой CSS подаётся на вход. Тут как с архивированием: сжимать сжатое уже никак.
На больших грязных CSS выигрываем от 2% до 5% без особой магии. На мелких обычно меньше. Правда, следует учитывать, что пока не все варианты группировок добавлены, а shorthand'ы покрыты только margin/padding, потому можно оптимистично добавить ещё 1%..2%.

Vladimir Moskva (fulc.ru)
30 апреля 2011, 01:11

хостинг с серверным JS найти крайне проблематично
VPS легко найти, кроме того, сжимать можно и на локальной машине.

Orcinus Orca (orcinus.ru)
30 апреля 2011, 12:16, ответ предназначен boltai-shaltai

Решил проверить на своем сайте.
До оптимизации: 1884 байта
После оптимизации: 1543 байта.
Получилась экономия в 341 байт.
Если бы там использовалась оптимизация по font-family, то код сократился бы очень сильно.

bolk (bolknote.ru)
30 апреля 2011, 12:41, ответ предназначен Vladimir Moskva (fulc.ru):

VPS легко найти
Это другие деньги.
кроме того, сжимать можно и на локальной машине.
Очень неудобно. Я часто редактирую мелочи прямо на удалённой машине.

bolk (bolknote.ru)
30 апреля 2011, 12:41, ответ предназначен Orcinus Orca (orcinus.ru):

Если бы там использовалась оптимизация по font-family, то код сократился бы очень сильно.
А попробуйте прогнать через YUI Compressor, потом через CSSO.

Сергей Крыжановский (skryzhanovsky.ya.ru)
30 апреля 2011, 21:18, ответ предназначен Orcinus Orca (orcinus.ru):

Добавил сегодня одну из схем группировок, теперь ваш CSS сжимается до 1308 байт. :)
На всякий случай отмечу: это не схема именно по font-family, просто в вашем случае именно повторы font-family удачно попали под новую группировку.

bolk (bolknote.ru)
30 апреля 2011, 22:41, ответ предназначен Сергей Крыжановский (skryzhanovsky.ya.ru):

Смотри, я нашёл как улучшить алгоритм:

.a { font-family: Tahoma; color: red }
.b { color: red }
.c { font-family: Tahoma; }

CSSO объединяет классы «.a» и «.b», что неправильно, там общее место — «color: red», оно короче, чем «font-family: Tahoma», объединять надо классы «.a» и «.c»!

bolk (bolknote.ru)
30 апреля 2011, 22:43, ответ предназначен Сергей Крыжановский (skryzhanovsky.ya.ru):

Более того, должно получиться вот так:
.a, .c { font-family: Tahoma }
.b, .a { color: red }

Сергей Крыжановский (skryzhanovsky.ya.ru)
30 апреля 2011, 22:53, ответ предназначен bolk (bolknote.ru):

Такую минимизацию уже проходил в ветке 1.0.x, после чего срочно переделал на менее опасную. :) В общем случае (обрати внимание на "в общем случае") нельзя нарушать порядок следования селекторов, это может плохо закончиться при комбинации классов у элемента. В твоём примере из abc получился acba, что *может* сломать вёрстку.

PS. Добавил бы подчёркивание в разметку комментов. :)

bolk (bolknote.ru)
30 апреля 2011, 23:40, ответ предназначен Сергей Крыжановский (skryzhanovsky.ya.ru):

Такую минимизацию уже проходил в ветке 1.0.x, после чего срочно переделал на менее опасную. :) В общем случае (обрати внимание на "в общем случае") нельзя нарушать порядок следования селекторов, это может плохо закончиться при комбинации классов у элемента. В твоём примере из abc получился acba, что может сломать вёрстку
Видимо, на ночь глядя, я не очень понимаю в чём опасность. Поясни на примере, пожалуйста!
PS. Добавил бы подчёркивание в разметку комментов. :)
Ну уж нет. Подчёркивание должно быть только в ссылках. :)

Сергей Крыжановский (skryzhanovsky.ya.ru)
1 мая 2011, 00:24, ответ предназначен bolk (bolknote.ru):

Пожалуй, самый наглядный пример:

test0.css: .t0 { color: red } .t1 { color: green }
test1.css: .t1 { color: green } .t0 { color: red }

test.html: <div class="t0 t1">test</div>

В случае с test0.css получишь текст зелёного цвета, а test1.css даст красный цвет.

Пример кажется простым и очевидным. И кажется, что "ну хорошо, в таких случаях не менять порядок, конечно, но наверняка иногда можно", но кажется так ошибочно. Распространи проблему на большой CSS, на сотни селекторов и тысячи свойств, да ещё и на множественные комбинации классов у элемента. Попытка безопасно перетрясти такое выливается в адову лапшу "частных случаев" с постоянной опасностью упустить какой-нибудь сотый случай, когда нельзя было даже дышать на селектор.

Может быть, в будущем снова залезу и что-то получится, но пока целью является гарантированное сохранение результата рендеринга даже в ущерб потенциальному отгрызанию размера.

bolk (bolknote.ru)
1 мая 2011, 00:35, ответ предназначен Сергей Крыжановский (skryzhanovsky.ya.ru):

Не вижу как это пересекается с моим примером. Можешь показать как с моим примером может получиться что-то плохое?

Сергей Крыжановский (skryzhanovsky.ya.ru)
1 мая 2011, 01:16, ответ предназначен bolk (bolknote.ru):

Жень, ведь специально выделил "в общем случае" и "может", а потом упомянул "частные случаи". В твоём примере ничего плохого. :)

На деле я просто не готов сейчас написать обстоятельно и убедительно на эту тему. Более того, вполне вероятно, что дую на воду после молока, и преувеличиваю опасности. Предлагаю вернуться к разговору после того, как CSSO исчерпает минимизации без смены селекторов, а я для этой области минимизаций составлю каталог.

bolk (bolknote.ru)
1 мая 2011, 10:57, ответ предназначен Сергей Крыжановский (skryzhanovsky.ya.ru):

Ok!

Orcinus Orca (orcinus.ru)
3 мая 2011, 06:01, ответ предназначен Сергей Крыжановский (skryzhanovsky.ya.ru):

Отлично смотрится. Удачных поисков в оптимизации.

C'est la vie (se-la-vy.blogspot.com)
5 мая 2011, 10:24

Всё бы замечательно, только ant`а таска для CSSO найти не удаётся...

Для YUI Compressor`а, например, есть (описан, например, на "Техногрете": http://www.artlebedev.ru/tools/technogrette/soft/eclipse-ant/ ), и очень удобно настроив один раз проект, потом оптимизировать все файлы автоматом при внесении изменений.
А так - всё выглядит очень здорово! Спасибо Вашей конторе за такой замечательный проект!
Так что ждём, надеемся и верим! :)

Сергей Крыжановский (skryzhanovsky.ya.ru)
7 мая 2011, 01:45, ответ предназначен C'est la vie (se-la-vy.blogspot.com):

Таски (плагины) для Ant / Maven удобнее будет делать после того, как релиз CSSO портируется на Java. Потому не сейчас, но обязательно. :)
Спасибо.

http://usedspareparts.ru/ (инкогнито)
15 мая 2011, 02:57, ответ предназначен Сергей Крыжановский (skryzhanovsky.ya.ru):

Сергей, еще момент.
Пробел перед !important.

se-la-vy.blogspot.com (se-la-vy.blogspot.com)
18 мая 2011, 19:11, ответ предназначен Сергей Крыжановский (skryzhanovsky.ya.ru):

Ясно. А если через Rhino прогнать?

Ваше имя или адрес блога (можно OpenID):

Текст вашего комментария, не HTML:

Кому бы вы хотели ответить (или кликните на его аватару)