Виталию Харисову посвящается
После перевода заметки «Оптимизируем CSS-производительность» и справедливых замечаний Виталия
Естественно, что скорость работы одиночного CSS-правила весьма высока, и даже десятки и сотни их не должны заметно замедлить работу браузеров. Поэтому нужно ставить эксперимент по работе с несколькими тысячами правил, иначе точность результатов будет весьма невысока. Использовать JavaScript для генерации HTML/CSS-кода не представляется разумным, ибо тогда придется учитывать еще и скорость работы JS-движка в браузерах, в итоге, эксперимент будет недостаточно чистым.
В конце концов, было решено сгенерить статичные файлы (порядка 300Кб), которые будут содержать достаточное число различных CSS-селекторов. Это самое «достаточное» число подбиралось по нескольким параметрам, в том числе: размер файла (гонять несколько Мб через браузер и интернет совсем не хотелось) и скорость работы HTML/CSS-кода в браузерах (она должна быть достаточно низкой, чтобы файлы в несколько сотен Кб уже заметно тормозили при открытии).
Далее. Размер кода для разных случаев должен различаться минимально, иначе могут быть погрешности, накладываемые просто скоростью работы с объемами данных (издержки парсинга). Для нескольких случаев, производительность которых сравнивалась, размер файлов различается не более, чем на 2–3%. В качестве основных случаев были выбраны: наличие или отсутствие тега перед названием класса или идентификатора в объявлении CSS-свойства.
Итоговые файлы содержат по 4096 объявлений различных CSS-классов (или различных идентификаторов), HTML-код содержит соответствующее количество блоков, у каждого свой индивидуальный класс (или идентификатор). Дополнительно проверялась скорость работы с простым наследованием узлов (div p
, CSS1) и селектор для выбора потомка первого уровня (div>p
, CSS2).
При тестировании браузеров нужно было, во-первых, открыть на клиенте соответствующую данному случаю страницу, а также как-то отследить время на отображение конкретно HTML/CSS-части (понятно, что оно не совпадает со временем открытия всей страницы, которое еще содержит некоторые накладные расходы).
Для этого была использована простая техника, подчерпнутая из этой статьи: перед объявлением CSS-блока запоминается текущая метка времени, после окончания HTML-блока, который должен отобразиться, запомненная метка вычитается из текущей. Таким образом, мы получаем (в идеале) время на отработку данных CSS-правил и кода, которыми ими описывается, на клиенте (плюс, возможно, еще какие-то более-менее постоянные расходы, которые нивелируются, если брать относительный, а не абсолютный выигрыш).
Конечно, каждую тестовую страницу можно подгружать в невидимом iframe
или даже AJAX-запросом. Но ведь мы хотим узнать, фактически, скорость рендеринга браузером CSS-правил и соответствующего кода, а это время будет расходоваться только при отображении страницы в окне браузера (это верно, по крайней мере, для Firefox). Поэтому подгружаемую страницу нужно отображать на экране (по возможности, максимального размера), чтобы отследить имеющуюся разницу. Далее запомненное время можно отправить родительской странице, где хранится вся матрица времен проверок.
Онлайн-версия тестов лежит по этому адресу: webo.in/tests/css-efficiency/, там можно посмотреть, собственно, всю методику уже в коде и скачать оффлайн-версию тестов в виде архива (чтобы лишний раз не гонять трафик).
Некоторые шаги по уменьшению влияния всех остальных факторов (кроме производительности браузеров для данного случая) были уже проведены при разработке методики выше. Однако, дополнительно тесты запускались по 10 раз в каждом из перечисленных ниже браузеров, чтобы свести уже статистическую погрешность не более, чем к 8–9%. В результате, хотелось однозначного ответа, какие именно CSS-селекторы в каких браузерах работают быстрее.
Ниже приведена большая таблица с результатами тестов, которые заключаются в среднем времени отображения страницы для различных вариаций селекторов и разных браузеров. Выделено время, меньшее по сравнению с аналогом. Хочется подчеркнуть, что имеет смысл только относительное ускорение использования одних типов селекторов относительно других в пределах одного браузера. Все времена даны в миллисекундах.
Сравнивать абсолютные значения в рамках данного эксперимента не представляется возможным, ибо каждому браузеру дополнительно нужно было расположить на странице несколько тысяч «плавающих» блоков с заданными размерами (float:left; width:20px; height:20px
, фон для которых и задавался): эта задача не имеет ничего общего со скоростью работы CSS-селекторов, но может отнимать существенное время у браузера на подготовку изображения страницы на экране (как видно, например для Opera).
Firefox 2 | Opera 9.5 | Safari 3 | IE 7 | IE 6 | IE 5.5 | |
---|---|---|---|---|---|---|
p.class | 308 | 5887 | 237 | 82 | 72 | 145 |
.class | 219 | 6456 | 225 | 78 | 70 | 149 |
p#id | 349 | 7377 | 338 | 91 | 87 | 156 |
#id | 214 | 7427 | 220 | 83 | 84 | 159 |
div>p.class | 519 | 9412 | 247 | 97 | 84 | 158 |
div>.class | 836 | 12886 | 257 | 95 | 81 | 159 |
div>p#id | 549 | 10299 | 247 | 105 | 92 | 172 |
div>#id | 858 | 15172 | 242 | 113 | 91 | 169 |
div p.class | 827 | 10706 | 256 | 97 | 84 | 161 |
div .class | 505 | 15864 | 247 | 95 | 86 | 160 |
div p#id | 772 | 11952 | 247 | 108 | 99 | 177 |
div #id | 948 | 13306 | 255 | 108 | 95 | 173 |
div.div p.class | 1001 | 10519 | 263 | 111 | 94 | 165 |
div.div .class | 1099 | 18742 | 253 | 105 | 92 | 166 |
div.div p#id | 1161 | 10989 | 266 | 117 | 95 | 181 |
div.div #id | 1247 | 15816 | 256 | 114 | 100 | 187 |
В таблице приведено время в миллисекундах для каждой селектора, затраченное браузером на его отображение (точнее, на отображение его тестового случая). Спасибо
Единственный вывод, который можно с твердостью сделать, это преимущество использования #id
перед p#id
(средневзвешенное по всем браузерам — 14%, спасибо .class
вместо p.class
(10%). Еще стоит обратить внимание на существенное (до 2,5 раз) ускорение при переходе от CSS1-селекторов к CSS2 (от div p
к div>p
, в тех браузерах, которые это поддерживают). Дополнительно стоит, наверное, отметить, что выборка элементов по классу работает, в целом, быстрее, чем по идентификатору (11%). Для средневзвешенного значения бралось следующая популярность браузеров: IE6 — 35%, IE7 — 35%, Firefox — 25%, Opera — 4%, Safari — 1%.
Все остальные выводы уже можно делать, анализируя данные из таблицы (чисел много, но какие-то более явные заключения из них вывести трудно, больше потому что IE всех версий стабильно выполнял все тесты примерно на одном уровне, а при его текущем доминировании оптимизация будет идти, в первую очередь, для него).
Если у кого-то появятся идеи, как можно грамотно расширить или уточнить тесты, — можно с удовольствием их обсудить.