Several months of work to improve Core Web Vitals on the home page of Mail.ru resulted in a 60% increase in the 75th percentile in Cumulative Layout Shift (CLS), boosting average session time by 2.7% and conversion rates of core sections by more than 10%.
Where we started
Mail.ru is one of the leading e-mail services on the Russian-speaking Internet and is in the top 5 sites in Russia in terms of traffic. Mail.ru is an important resource for many people. It receives several hundred million visits per month, and is a portal from where people can access email, news, social media, performance internet searches and more.
Mail.ru wanted to provide its visitors with a high quality user experience, so work began to improve Core Web Vitals. Before discussing our optimization strategy, a few technical details of the Mail.ru home page should first be noted.
Though the project had long been developed using our in-house templating engine Fest, we began to migrate to Svelte 3 in 2019.
Svelte implements reactivity in a way that doesn't use Virtual DOM, which makes it less resource-intensive. Svelte's approach removes unused functions from production bundles because the code implementing them isn't generated by the compiler if the functions aren't used. Unused code is removed during compilation, resulting in smaller bundles. This may help reduce Total Blocking Time (TBT) during page startup.
Tracking performance metrics
Before optimizing Core Web Vitals, it's helpful to evaluate performance in the field. Before Core Web Vitals, we tracked other metrics, such as First Contentful Paint (FCP), in our internal performance dashboard.
Our metrics collection script was modified to collect Core Web Vitals and transmit them to our performance dashboard for visualization. In line with Google's recommendations, our script uses PerformanceObserver API to obtain metrics, which is part of the universal frontend "Platform" inside Mail.ru.
The dashboard displayed the following metrics for users (mean values for the week of 15-21 March 2021):
Metrics group name | Core Web Vitals | Other Web Vitals | |||||
---|---|---|---|---|---|---|---|
Metric name | LCP | FID | CLS | FCP | TBT | TTI | |
Share of users in accordance with Core Web Vitals thresholds | good | 52% | 92% | 33% | 35% | 42% | 43% |
needs-improvement | 19% | 5% | 23% | 38% | 16% | 25% | |
poor | 29% | 3% | 44% | 27% | 42% | 32% |
Improving Core Web Vitals
While plenty of guidance exists for improving Core Web Vitals, every project has unique challenges. For the Mail.ru home page, the following opportunities were identified:
- Implementing placeholders for ad banners to reduce CLS.
- Using server-side rendering (SSR) to reduce Largest Contentful Paint (LCP).
- Code splitting to reduce LCP and First Input Delay (FID).
Skeletons for CLS improvement
CLS was one of the worst performing field metrics for the Mail.ru home page. Subsequent profiling of this page in the Performance panel of Chrome's DevTools revealed that ads were the source of the problem. To improve layout stability, our team decided to use placeholders to reserve space for ads before they load.
When implementing placeholders, the first step is to determine the dimensions of the content that will replace them. Luckily, the desktop version of Mail.ru home page has strictly documented sizes for ads. After talking with the design team, SVG-animated UI skeletons were used as placeholders as they reduce the perceived load time of the content.
The return of SSR
To ease the transition from Fest to Svelte, we incrementally rewrote the existing project rather than start over. By March 2021, we had migrated most of the frontend to Svelte, and eventually brought SSR to our production application after triaging and fixing backend performance issues.
After implementing SSR, the team discovered the cause of CLS regression that initially went unnoticed: the news section was not inserted at the moment of rendering the first content on the page. There was a delay between the initial painting of the page markup provided by the server and the insertion of news section on the client. This behaviour resulted in an ad skeleton shift, which worsened CLS.
Although Chrome's DevTools showed Layout Shift events, we couldn't find the reason for it at first. Though SSR itself wasn't the problem, it helped in discovering the solution later on. Fixing the code responsible for the painting delay improved layout stability of the news component.
Another effect SSR can have on CLS is the movement of components before and after hydration, which can lead to further layout shifts. We encountered this on the mobile version in particular and it required paying special attention to the hydrated component markup. A good solution to this problem was transferring as much display logic from JavaScript to CSS when possible.
Code splitting and unused polyfills
To improve the perceived page load speed, work was required to decrease LCP and FID values. One way to achieve this is through code splitting. In addition to the Mail.ru home page itself, our team is developing a widget for portal navigation. It is currently embedded in many of our company's projects.
For historical reasons, the widget is inserted at the very beginning of the page as a synchronously loading script. The share of polyfills in this script grew over time. To limit the negative performance effects of loading these polyfills, we implemented code splitting for both modern and legacy browsers.
We decided against the module
/nomodule
pattern for loading JavaScript bundles for modern or legacy browsers, as the <script>
element's type="module"
attribute didn't target browsers that were modern enough for our needs. To address this, Mail.ru uses an in-house tool for identifying modern browser versions on the backend, and can adapt to those browsers accordingly.
Once browsers could be identified in the backend, we implemented code splitting for modern and legacy browsers. The result was a 43.3% reduction in size of the synchronously-loaded JavaScript widget for modern browsers. This practice has been applied to some other portal scripts as well.
In addition to bundle size reduction and positive effects on Core Web Vitals, code splitting improves the developer experience as well. Only 3.5% of our users use legacy browsers and that share is on a downward trend, so implementing code-splitting allowed our developers to use the latest browser APIs without introducing the polyfill bloat necessary for legacy browsers to all users.
Results
After the optimization effort, we observed the mean values for the week of 24-30 May 2021 in our field data:
Metrics group name | Core Web Vitals | Other Web Vitals | |||||
---|---|---|---|---|---|---|---|
Metric name | LCP | FID | CLS | FCP | TBT | TTI | |
Share of users in accordance with Core Web Vitals thresholds | good | 58% (+6%) | 93% (+1%) | 93% (+60%) | 43% (+8%) | 49% (+7%) | 51% (+8%) |
needs-improvement | 18% | 4% | 3% | 34% | 17% | 24% | |
poor | 24% | 3% | 4% | 23% | 34% | 25% |
The graphs below show changes in web page performance metrics values according to the "Platform". Note the two important dates on the graphs:
- 23 March 2021: the release of iteration with the last page sections migrated to Svelte;
- 19 April 2021: the release of iteration with returned SSR and layout modified to correct CLS regressions.
The decrease in values from May 1 to May 10 is due to May holidays in Russia.
Results obtained using the "Platform" are in line with the growth of metric values in Chrome UX Report (CrUX).
A comparison of mean user session duration values a week before the roll-out of initial improvements and a week after the roll-out shows 2.7% growth. Moreover, there is an overall significant increase in conversion in most sections of the page. In particular, conversions to the Mail.ru email app increased by 11.6%, the conversion of the news section increased by 13.5%.
181%
Boost of share of good CLS threshold
2.7%
Higher mean session duration
13.5%
Increase of news section conversion rate
The most unexpected result we got was a 17.4% increase in the Click-Through Rate (CTR) of the marketing banner (its rendering time was significantly reduced by the introduction of SSR and preload tags).
After analyzing the rest of the sections on the page, we noticed significant performance improvement in the vast majority of them. Even for sections such as Weather and Coronavirus—which are not key on our page—we see an increase in conversion by 9.6% and 9.5%, respectively.
Conclusion
Improving performance is challenging in that the work involved may be prolonged. You should regularly monitor changes in metrics over time and ensure that all new product features don't cause regressions in Core Web Vitals. To achieve this, we monitor changes in Core Web Vitals in our performance budget.
Most importantly, we stressed the importance of Core Web Vitals to all members of our product team, from managers and designers to testers and QA. Each team member should be aware of performance metrics and be empowered to improve them. We also incorporate performance optimization objectives into our business processes on a regular cadence. Successfully providing a high-quality user experience is only possible through a joint effort by all team members.