Выбор эффективных селекторов на основе вычислительной сложности
Учитывая особенности обработки CSS, в частности, соответствие RTL и эффективность селекторов, как следует писать селекторы исключительно с точки зрения производительности движка рендеринга?
Это должно охватывать общие аспекты и включать использование или избегание псевдоклассов, псевдоэлементов и селекторов отношений.
1 ответ
Во время выполнения HTML-документ анализируется в DOM-дереве, содержащем N
элементы со средней глубиной D
, Существует также в общей сложности S
Правила CSS в применяемых таблицах стилей.
Стили элементов применяются индивидуально, что означает прямую связь между
N
и общая сложность. Стоит отметить, что это может быть несколько компенсировано логикой браузера, такой как эталонное кэширование и переработка стилей из идентичных элементов. Например, к следующим элементам списка будут применены те же свойства CSS (при условии отсутствия псевдоклассов, таких как:nth-child
применяются):<ul class="sample"> <li>one</li> <li>two</li> <li>three</li> </ul>
Селекторы сопоставляются справа налево для соответствия отдельным правилам - т. Е. Если самый правый ключ не соответствует определенному элементу, нет необходимости дополнительно обрабатывать селектор, и он отбрасывается. Это означает, что самый правый ключ должен соответствовать как можно меньшему числу элементов. Ниже
p
дескриптор будет соответствовать большему количеству элементов, включая абзацы за пределами целевого контейнера (что, конечно, не будет применять правило, но все равно приведет к большему количеству итераций проверки приемлемости для этого конкретного селектора):.custom-container p {} .container .custom-paragraph {}
Селекторы отношений: селектор потомков требует до
D
элементы для повторения. Например, удачное совпадение.container .content
может потребоваться только один шаг, если элементы находятся в родительско-дочерних отношениях, но дерево DOM необходимо будет пройти через весь путь доhtml
прежде чем элемент может быть подтвержден несоответствие и правило безопасно отбрасывается. Это относится и к цепочечным селекторам потомков, с некоторыми допусками.С другой стороны,
>
выбор ребенка,+
соседний селектор или:first-child
все еще требует, чтобы дополнительный элемент был оценен, но имеет только подразумеваемую глубину один и никогда не потребует дальнейшего обхода дерева.Определение поведения псевдоэлементов, таких как
:before
а также:after
подразумевает, что они не являются частью парадигмы RTL. Логика заключается в том, что псевдоэлемента как такового не существует, пока правило не даст указание вставить его до или после содержимого элемента (что, в свою очередь, требует дополнительных манипуляций с DOM, но для соответствия самому селектору не требуется никаких дополнительных вычислений).Я не мог найти информацию о псевдоклассах, таких как
:nth-child()
или же:disabled
, Проверка состояния элемента потребовала бы дополнительных вычислений, но с точки зрения синтаксического анализа правила имело бы смысл только исключить их из обработки RTL.
Учитывая эти отношения, вычислительная сложность O(N*D*S)
должен быть снижен в первую очередь за счет минимизации глубины селекторов CSS и адресации пункта 2 выше. Это приведет к значительно более сильным улучшениям по сравнению с минимизацией количества правил CSS или только элементов HTML.
Мелкие, предпочтительно одноуровневые, специфические селекторы обрабатываются быстрее. Это подняло Google на совершенно новый уровень (программно, а не вручную!), Например, редко есть селектор с тремя ключами, и большинство правил в результатах поиска выглядит так
#gb {}
#gbz, #gbg {}
#gbz {}
#gbg {}
#gbs {}
.gbto #gbs {}
#gbx3, #gbx4 {}
#gbx3 {}
#gbx4 {}
/*...*/
^ - хотя это верно с точки зрения производительности движка рендеринга, всегда есть дополнительные факторы, такие как издержки трафика, анализ DOM и т. д.