Contributing to Speedometer 3.0: Capturing real-world challenges on the web
In collaboration with cross-industry browser vendors under the Speedometer governance policy, the Microsoft Edge team is very excited to have contributed to the recently released version 3.0 of Speedometer, as announced on browserbench.org.
First released in 2014, Speedometer is a popular browser benchmark and a key driver of recent browser performance improvements. Version 3.0 has several improvements to the test runner and adds many new tests over version 2.1. An important goal was to capture common, present-day challenges faced by developers by incorporating new variants, frameworks, and modern usage scenarios to the Speedometer tests.
The Microsoft Edge Team contributed a new Complex DOM set of tests to meet these goals. Our aim was to represent the scalability challenges faced by modern web applications, and to drive performance improvements for these applications across the ecosystem.
Motivation: The challenge for modern web applications
Over the past few years, the Edge team collaborated with several Microsoft web application teams to provide expert recommendations for addressing scalability and performance issues. We did this by delving deep into performance profiles, application software stacks, and architecture.
These investigations have consistently shown that the complexity of the DOM and CSS rules is an important driver of end-user perceived latency. Inefficient patterns, often encouraged by popular frameworks, have exacerbated the problem, creating new performance cliffs within modern web applications. The new Complex DOM tests perform DOM mutations in the context of a large DOM tree, which trigger a cascade of costly CSS selector matching operations and style recalculations.
To facilitate the real-world representation of the Complex DOM tests, the Edge team took a data-driven approach to collect more data on DOM sizes and CSS selectors.
DOM sizes – How large is large?
The table below lists some data on DOM tree sizes and their maximum depth in familiar web pages and web application interfaces. We also got inputs on DOM sizes from Adobe in some of their web applications, recognizing the need to capture the performance challenges in the presence of large DOM trees. This gave us a good idea of the DOM tree sizes that would surface rendering performance issues in a benchmark test.
Webpage | DOM size | Max depth |
---|---|---|
amazon.com | 3746 | 22 |
youtube.com | 9082 | 30 |
Google results page | 3458 | 48 |
reddit.com | 4460 | 21 |
MDN Promises article | 4167 | 17 |
walmart.com | 3382 | 25 |
Facebook (after scrolling) | 9957 | 63 |
Gmail (opened email) | 3494 | 69 |
HBO Max | 5478 | 19 |
Airbnb.com (login and open filters) | 3388 | 38 |
Adobe Photoshop (Quick Actions panel) | 6751 | ≥ 24 |
Adobe Photoshop (Text Box new) | 6331 | ≥ 31 |
bbc.com/news/world | 3898 | 26 |
nationalgeographic.com | 4111 | 23 |
Google docs | 3558 | 15 |
Google sheets | 5730 | 18 |
Stack overflow post | 2521 | 19 |
Microsoft Outlook | 2870 | 32 |
Microsoft Teams | 2542 | 32 |
apple.com/apple-vision-pro | 2857 | 18 |
2488 | 59 | |
timesofindia.indiatimes.com | 2789 | 22 |
CSS selectors – How complex is complex?
Complex CSS selectors are composed by combining several simple selectors using combinators like the descendant, child, adjacent and the sibling combinators. They cause browsers to perform complex matching operations and costly style recalculations. For more details about CSS selector performance, see The truth about CSS selector performance.
The Edge team collected data on CSS selectors that occur in real-world web applications, pointing us to CSS selectors that challenge application performance. A few representative ones are listed below.
Microsoft Outlook:
.r9gx1vl:not(:checked) ~ .fui-Radio__indicator > *
.f17xb19f > :not(.fui-CardPreview__logo)
.appContainer-459 ::after
Microsoft Teams:
.r1no3lux pre[class^='language']>code
.fiiet6c span:nth-child(1)
.f15hebdy>div>div>div
.flp1aja span:not(.giphy-gif) img:not([itemtype*="Emoji"])
.f1mj8y37>*:not(.ms-StackItem)
Examples from other Microsoft apps:
#root ~ script[src*="cdn-client.medium.com"] ~ div > div:not([role]):not([tabindex]):not([id]):not([class*="jfk"]):not([class*="gtx"])
._1WiHgiOg6qjeGNfJmJm0hu .o365cs-base [class^="ms-Icon--"]::before
While the performance challenges posed by complex CSS selectors are widely observable, they manifest differently when they are used in conjunction with other CSS properties or technologies like Web Components.
Variations of the Complex DOM framework
For technologies like Web Components that support Shadow DOMs (an encapsulation mechanism for isolating parts of a DOM tree from the code effects of one another), performance challenges can come from Constructable stylesheets, CSS variables, and fallbacks.
We customized the Complex DOM framework for the Web Components and LIT based implementations to surface these challenges. We also provided two flavors of the Complex DOM framework, one that nests a sizeable chunk of the DOM tree within a CSS stacking context and another that does not as this impacts the rendering order of HTML elements in a DOM tree, which in turn impacts performance in large web applications.
The Complex DOM test
The Complex DOM test is based on a complex application shell, which embeds the TodoMVC application, as shown in the image below:
The key idea is to perform the simple and seemingly isolated actions of the TodoMVC application, such as adding, checking or deleting items, within the broader context of a large and complex web application. This simulates the scalability challenges observed when end users interact with real-world web applications.
The application shell used in the Complex DOM test is fashioned after a generic productivity application to have a real-world look-and-feel, leveraging Adobe’s Spectrum CSS library in its implementation. It consists of a scrollable sidebar element that embeds a large DOM tree, several complex CSS selectors (around 70), and a realistic ribbon menu – totaling to a little more than 6000 DOM elements.
Representing a large DOM structure
The Edge team collaborated internally with Microsoft’s Tensile team to build the Complex DOM application shell, borrowing heavily from their parametrized DOM tree generator. The Tensile framework is designed with the goal of representing the (realistic) costs incurred during page load, style recalculation, layout, and paint by real-world web applications. Early data indicates that it is an accurate predictor of overall performance for applications with complex CSS and large DOMs.
In a case study shipping the Persona control in Fluent, the Tensile framework reported a 30% performance improvement in scripting and styling across two versions of the Persona control implementation which is reflective of the 24% improvement observed in an actual application using the control.
The ribbon contains about 469 descendent elements, and provides drop-down popover menus, for seven relevant and realistic operations. Two of the sample popovers, reminder and backlog, are shown in the images below:
Representing complex CSS selectors
The complex DOM application shell consists of about 70 CSS selectors which are constructed by composing them with up to six simple selectors. Some selectors style todo list elements while others style the popovers in the ribbon. They are designed such that all of them either fully match or partially match a todo list element.
A partial match is when a sub selector matches a DOM element, but the entire selector does not. This ensures that the Complex DOM shell captures the performance issues caused by both matching and partially matching CSS selectors to well represent real-world user interactions in complex stateful situations.
For example, consider the following two selectors:
.todo-area .todo-list li .toggle:checked + label
.reminder-group .high-priority:hover > :checked ~ label
The first selector matches an element in the todo list whereas the second selector does not because no todo list element has the .high-priority
class. However, a todo element would partially match the rightmost portion of the selector, i.e., :checked ~ label
.
Try it out!
We are eager for you to check out Speedometer 3.0. We think that the collaboration between cross-industry browser vendors has been very effective in capturing real-world challenges on the web in browser benchmarks like Speedometer.
We look forward to continuing this collaboration and making the web more performant for you all! Feedback, comments, new ideas and suggestions for improvements are very welcome! Please send them to the Speedometer GitHub repository.
– Luis Fernando Pardo Sixtos, Issack John, Sean Monahan, Sulekha Kulkarni, Leo Lee, Alex Russell