Table of Contents
Overview of the Core Web Vitals
Web Vitals is an initiative by Google to provide unified guidance for quality signals that are essential to delivering a great user experience on the web.
The Core Web Vitals, as of Winter 2022, are:
- Largest Contentful Paint (LCP): Measures the time from navigation to the time when the browser renders the largest bit of content from the DOM.
- First Input Delay (FID): Measures the time from when a user first interacts with your site (i.e. when they click a link, tap on a button, or use a custom, JavaScript-powered control) to the time when the browser is actually able to respond to that interaction.
- Cumulative Layout Shift (CLS): Measures the sum total of all individual layout shift scores for every unexpected layout shift that occurs during the entire lifespan of the page.
What is FID
Whether you’re going on a date or meeting your in-laws for the first time, we all know first impressions count. On your websites, a good first impression could make the difference between creating a lifelong & loyal user and them never coming back. We see the application of this knowledge in the real world, you may have come across the term supermarket psychology. Greeters, the fresh smell of the bakery pumped over the front doors as you walk in, and the placement of the premium items within direct eye line on the shelves.
What your FID is measuring is that first impression.
It is important to note that FID can only be collected through real user data. This metric is a reflection of actual human interaction on your site and cannot be measured with synthetic. Total Blocking Time (TBT), however, can be collected via synthetics and also measures the effects of interactivity.
First Input Delay measures time between the 1st interaction a user makes and how long it takes for the browser to respond. Pressing buttons, using checkboxes, clicking a link, or using a custom JS powered control are all examples of items measured by FID, whereas scrolling & zooming will not be - this is a separate area we can measure performance in. An ideal FID response time is 100ms or below. For context, a human blink is 300ms.
(Source: Google, https://web.dev/fid/)
On the graph above, we see resources loading in represented by grey lines, and the Main Thread where the browser processes events and paints content. These tasks such as script executions (can be long or brief) are represented by the yellow boxes along the X axis.
One thing to keep in mind with measuring FID is that the same user can click the same button at different times, and the FID will depend on the work currently being done by the main thread. Some users will have no FID values (e.g. A), some users will have low FID values, some users may have high FID values (e.g. B). What Google looks at is the FID experience at the 75th percentile, so that’s 75% of the users on your site experiencing a response to their first action within 100ms. One of the main causes of poor FID score is JS execution.
How to Optimize for FID
Blue Triangle allows you to aggregate the experience of all users visiting your page using the RUM Aggregate Waterfalls:
- Function Tracing
- Function & Object Level tracing
These trend and average how long each resource is taking, and allows us to identify long running JS tasks that might keep the main thread busy and contribute to a poor UX/FID. We can also help to perform retrospectives on whether the implementation of any recommendations we’ll go through have had any impact on real user behavior (traffic, revenue, and conversions).
Examples:
Quick Wins
Without spending significant development time, what kind of performance gains could we reap?
- Minify JS, CSS, and HTML. Reducing the content the main thread has to parse in order to deliver and act on these resources. Every byte counts. We’ve managed with one customer to reduce the weight of the page by 10% simply by omitting unnecessary chars/spaces/line breaks. At scale, this can have a real impact in terms of content delivery costs via a CDN where you might pay per gigabyte.
- Using HTML attribute Preload. This allows you to request that the browser prioritizes critical content on your page, especially items that are not easily discoverable (those inside CSS, JS requested, larger images that are considered critical content).
- Async & defer attributes are HTML attributes that you can apply to your <script> tags when loading JS. Think of these as traffic signals that control the stop and go of how JS downloads/executes. Both tell the browser not to block HTML parsing whilst downloading. Think about how we open the middle highway lane during peak city traffic times. It’s always available to use, and it has its own limits, but it can let a bigger portion of traffic through if we utilize it
Async: Once downloaded, it executes as soon as the main thread is ready (social media, ads, where the order of exe doesn’t matter)
Defer: also download asynchronously, but waits for the entire page to be downloaded and rendered. They execute in the order they’re on the page. Generally use defer for non-critical resources. - Keep 3rd parties in check. Prioritization of critical resources (i.e load what offers the greatest value to users first). Does content in the footer of a website need to load before user generated content in the form of reviews, or is the browser’s resource time better spent loading content that we know drives clicks. Consider taking a pass on scripts that don’t add clear value to your website. Many plugins play a key role in the uplift of conversion, traffic, and other metrics, but can you quantify the impact that the addition of the tag is having on our website? One thing we can do at Blue Triangle with SLA alerts.
Moderate Effort
These will likely require development resource.
- Lazy loading.The idea is that you load non-critical resources where necessary, keep in mind UX.
For example, we’re on a Product Page. We want to check whether a store has that product in stock, and we use a 3rd party service to do that. Knocking back the loading of this resource until a user shows intent to interact, or past our initial page load helps keep the main thread more responsive.
- Static site generation where possible. Best for pages that aren’t changing often (i.e blogs).
- Code splitting. This involves splitting larger libraries into bundles or components which can then be loaded on demand or in parallel.
- Code optimization. Divide long tasks into smaller asynchronous ones - user interaction to be processed in between these breaks in execution. Well-optimized code runs the best it can on all devices, poorly optimized code gives a weighted poor experience for users with lower end devices. You don't control the devices that connect to your website, but you can control how performant your code is.
Complex Optimization Opportunities
These recommendations will require infrastructure & code changes.
- Utilizing web workers allows scripts to run CPU intensive workloads in the background to prevent scripts from blocking one another on the main thread. They can communicate via an API. They don't manipulate the DOM directly, but they do have access to certain browser APIs such as network requests & browser storage.
- Server-side rendering. Move logic to server-side and delivering a ready made page for the user (but be aware on the effect this has on TTFB).
- Revise polyfills usages. Are users on modern browsers downloading outdated resources they do not need?
- Optimize non-critical JS. We may defer and deprioritize, but this doesn’t mean we shouldn’t pay attention to the non-critical JavaScript, going through the exercises of optimization (dividing long tasks into smaller ones) will all contribute to a positive UX past the point of just FID.