Ever opened an article and started reading, only to lose your spot because you were bumped down the page? This annoying occurrence is the result of layout shift, one of many performance issues that can crop up without consistent care and attention.
Improving the experience of our users is always a top priority at The Washington Post. With Google’s focus on user-centric performance metrics via new page experience signals called Core Web Vitals (CWV), we can better monitor and iterate on those experiences.
CWV signals are currently being rolled out globally. They consist of three new performance metrics: Largest Contentful Paint (LCP), Cumulative Layout Shift (CLS) and First Input Delay (FID). We set a target to reach the highest threshold across all three metrics by August 2021, as Google’s rollout of the new signals is set to be completed by the end of the month.
For publications like The Post, which need to balance rich advertising, rich content and page speed, CWV poses an interesting challenge: How do we ensure a performant experience on all pages across our domain in the short term? And, looking ahead, how can we bake good performance and attention to UX into our long-term processes and culture?
Last summer, the engineering team at The Washington Post began exploring just that. Since then, we’ve seen significant lifts across all three scores.
To accomplish this positive shift, we put our users at the forefront of our engineering and design practices. Here are some key takeaways.
Understand the baseline
We began by determining a baseline for our CWV scores across our site using several different monitors to understand the complete picture. Luckily, there are a lot of awesome tools to help.
Step 1: Identify Patterns with GSC
The Google Search Console dashboard for CWV provided a good first pulse. This allows us to drill down into our less-performant urls and begin to identify patterns in templates or features.
Step 2: Get more granular segments with real-user data
Next, we collaborated with our Analytics team to set up dashboards that would show us an approximate distribution of scores for real users. This gives us more granular insight to triage issues on lower connection speeds, varying devices, etc.
Step 3: Automate and monitor release impact
We highly value continuous deployments and set up synthetic monitoring using Calibre App against our common page templates, with automated alerts going to Slack when we fell below our threshold. This allows us to gauge impact of each release so we can #alwaysbeshipping.
Make it a priority and assemble the team
Communication and a shared commitment to deliver high-quality user experiences are the cornerstones of our success. From engineering to design to advertising and our newsroom, web vitals became a common language and a common goal through a series of communication and alignment methods:
- Recurring (and actionable) checkpoints across departments and teams to check in on progress, flag concerns and share tips
- Slack channel for sharing web vitals wins, resources and questions
- Company-wide presentations on web vitals in town halls
Getting company buy-in for performance work is possible by illustrating to stakeholders how CWV will benefit customers, increase the bottom line and speed up engineering productivity to ship more features, faster! It’s a win-win-win.
Fix the things!
We took several strategic steps to improve CWV scores at The Post.
Optimize Rendering of Main Images for LCP
We reworked the way we rendered the main image in our standard article layout, and as a result, it was the biggest improvement we saw in LCP.
How it worked:
- Preloaded the img element’s srcset
- Used an LQIP (low-quality image placeholder) in the form of a blurred svg as the background-image of the image element until the high-res request loaded
- Assigned the attribute decoding=”async” to the img element
These changes resulted in an improvement to our LCP score that was immediately noticeable.
Reserved Space for Components to Minimize CLS
Anywhere we used lazy loading, we used a placeholder element with a min-height — and potentially min-width — to reserve the space so the element would not jump in and push content elsewhere on the page. We invested in skeleton states to improve the user experience for our readers. This is one of those techniques that became a pattern for us in our quest to improve our CLS scores.
One example of this execution is with our advertisement placeholder. Previously, ads would jump into the slot and push content down the page, which could be frustrating for users, particularly on mobile devices or on smaller displays.
Improving our CLS score required close collaboration with the advertising team. To evaluate impact, we developed and ran extensive A/B tests that served different creative with predictable sizes into the slot for a split segment of users. By analyzing the CWV and broader impact, we were able to make data-driven business decisions. In most cases — and to our surprise — serving predictable creative sizes increased revenue and we were able to commit several units to a set size and eliminate CLS. By opting to serve larger ad sizes (300×600 units only instead of a combination of multiple sizes, which caused a layout jump), we saw higher CPMs. We also eliminated several ad format types that were jumpy. These were traditionally poor performers with our users. We replaced those formats with units that loaded fully in view, resulting in higher ad viewability metrics and, ultimately, higher engagement and improved ad performance.
As the page loads, min-height is reserved with a skeleton state for inline ads:
Because of this, the ad can be fully loaded in without impacting CLS:
Code-splitting for Faster FID
While we have made continuous improvements to our FID, we found opportunities to further enhance the score by utilizing code-splitting. We were able to ensure that, on any given page, unnecessary code was excluded from our JavaScript or CSS bundles, making our files lighter and our pages faster.
FID is described as a phenomenon that “happens because the browser’s main thread is busy doing something else, so it can’t (yet) respond to the user. One common reason this might happen is the browser is busy parsing and executing a large JavaScript file loaded by your app.”
By leveraging Next.js dynamic imports, we can conditionally load the JavaScript for components that are needed by each page. We took a similar approach to code-splitting CSS with updates to our webpack build:
Maintain, maintain, maintain
As with many things, improving CWV scores is not something you do once and then move on. We’re working at The Post to integrate CWV into our ongoing product, design and development processes, in addition to regular review of changes in our scores. It’s an ongoing effort.
We were able to introduce CWV as a new set of standards in cross-team collaboration — and dedicate resources to maintaining these standards. This will serve as a point of reference for other cross-team initiatives in the future. Now, we’re looking at structuring other projects the same way, for example, on web accessibility.
This article originally appeared on The Washington Post Engineering blog and is republished with permission.
Want to share CWV tips, interested in working with us, or just feel like saying hi? 👋
Contact us at [email protected] and [email protected].
This project wouldn’t be made possible without the hard work of this outstanding team: Holden Foreman, Robyn Bortz, Anna Scalamogna, Taylor Scott, Christopher Kankel, Erika Johnson, Hannah Mahon, Amanda Bozzi, Arturo Silva, Dan Weaver, Joey Weed, Sarah House, Amanda Hicks, Ted Cook, Thomas Chan, Tommy Lisiak, Eric Lin, Hope Tambala, Ryan Luu, Leo Dominguez, Nathan Walker, Gregory Auld, Ryan Coughlin, Matt Callahan, Dave Merrell, Jeff Turner, Julie Bacon and Kat Styons.