Статьи

Перевод: Николай Мациевский aka sunnybear
Опубликована: 27 февраля 2008

Разгоняем CSS-селекторы: стоит ли?

Виталию Харисову посвящается

После перевода заметки «Оптимизируем CSS-производительность» и справедливых замечаний Виталия  vithar, я решил поставить серию экспериментов по скорости работы 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 2Opera 9.5Safari 3IE 7IE 6IE 5.5
 
p.class30858872378272145
.class21964562257870149
 
p#id34973773389187156
#id21474272208384159
 
div>p.class51994122479784158
div>.class836128862579581159
 
div>p#id5491029924710592172
div>#id8581517224211391169
 
div p.class827107062569784161
div .class505158642479586160
 
div p#id7721195224710899177
div #id9481330625510895173
 
div.div p.class10011051926311194165
div.div .class10991874225310592166
 
div.div p#id11611098926611795181
div.div #id124715816256114100187
 

В таблице приведено время в миллисекундах для каждой селектора, затраченное браузером на его отображение (точнее, на отображение его тестового случая). Спасибо  dmsys за таблицу в картинке.

Выводы

Единственный вывод, который можно с твердостью сделать, это преимущество использования #id перед p#id (средневзвешенное по всем браузерам — 14%, спасибо  vithar, в пересчете для России получается 9%). Также можно с некоторой уверенностью говорить о использовании .class вместо p.class (10%). Еще стоит обратить внимание на существенное (до 2,5 раз) ускорение при переходе от CSS1-селекторов к CSS2 (от div p к div>p, в тех браузерах, которые это поддерживают). Дополнительно стоит, наверное, отметить, что выборка элементов по классу работает, в целом, быстрее, чем по идентификатору (11%). Для средневзвешенного значения бралось следующая популярность браузеров: IE6 — 35%, IE7 — 35%, Firefox — 25%, Opera — 4%, Safari — 1%.

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

Если у кого-то появятся идеи, как можно грамотно расширить или уточнить тесты, — можно с удовольствием их обсудить.

Читать дальше

Все комментарии (habrahabr.ru)