- PVSM.RU - https://www.pvsm.ru -
HTML документ загруженный в browser есть дерево DOM элементов и набор CSS правил. Каждое CSS правило это пара — селектор (selector) и список свойств (list of properties).
Мы мало задумываемся над тем, а собственно чего стоит нарисовать HTML документ c вычислительной точки зрения? Знания про то что думатель — думает, а неонка у нея унутре ярко светит сквозь opacity:0.5 элементы бывает явно не достаточно.
Собственно про это и есть данные статьи — про вычислительную сложность (computational complexity) отображения HTML и CSS. Хочу отметить что я использую свой собственный опыт имплементации HTML/CSS rendering engines (HTMLayout и Sciter), но вычислительные проблемы в данной области универсальны — определяются самой природой HTML и CSS спецификаций.
Представим себе HTML документ который после парсера превратился в DOM дерево состоящее из N элементов. Система стилей данного документя состоит из S CSS правил. Тогда вычислительная сложность [1] процедуры назначения стилей всем элементам DOM выражается так:
O( N * S * D )
Где D это метрика «глубины» (depth) дерева и используемых селекторов.
В качестве примера рассмотрим такое «замечательное» правило:
body * { background:red; }
'*' — каждому элементу внутри <body> присвоить красный цвет подложки. Практической пользы от такого правила конечно чуть но для иллюстрации то что нужно: берем n-ый элемент DOMа и перебираем всех его родителей (в глубину) на предмет body тэга. И так для каждого элемента. Если таких правил всего S то и имеем формулу приведенную выше.
В принципе N*S*D не так уж страшно в статическом случае — вычислили раз и забыли. Но в случае частых динамических измененний возможны проблемы. Скажем если поменять класс элемента-контейнера то для всего его поддерева нужно пересчитывать стили. А это опять в общем случае O( N * S * D )
задача.
Конечно CSS имплементации пытаются оптимизировать процесс перерасчета стилей но это не всегда удается. Основной метод борьбы с O(N...) проблемами это использование кеширования результатов. Скажем при определении стиля элемента можно проверить предыдущий элемент и если он «похож» на искомый то взять его стиль (если он определен). Но этот трюк спотыкается например на правилах типа li:nth-child(even)
. Причина я думаю очевидна.
WebKit например вообще не поддерживает динамические атрибут-селекторы. Например если вы захотите преключать режим отображения документа c помощью изменения значения некоего DOM атрибута «mode» и пары правил вида body[mode=first] .widget {color:red}
и body[mode=second] .widget {color:green}
то у вас ничего не получится (в WebKit). Такая вот оптимизация в этом движке.
Рекомендации по оптимальному использованию стилей:
ul.cls2 li
хуже чем селектор ul li.cls1
в том смысле что в первом случае просматриваются все li элементы и их родители на предмет ul.cls2, а во втором набор li для которых выполняется поиск в глубину уже — только для тех li у которых задан class=cls1.
.cls2 .cls1
«хуже» чем селектор .cls2 > .cls1
. Во втором случае проверка на соответствие всегда будет ограничена самим элементом и его родителем. В первом же случае глубина просмотра потенциально до корневого <html> включительно.… а это уже тема следующей статьи если кому-то эта тема интересна.
Автор: csmile
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/html/4119
Ссылки в тексте:
[1] вычислительная сложность: http://ru.wikipedia.org/wiki/%D0%92%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D1%81%D0%BB%D0%BE%D0%B6%D0%BD%D0%BE%D1%81%D1%82%D1%8C
Нажмите здесь для печати.