More coming soon.
At Kanopi, we closely monitor (a subset of Web Vitals) during development which was introduced in June 2021 into Google’s ranking algorithm. Ensuring healthy Web Vitals throughout the build and/or maintenance is of paramount importance and requires a shift not only in how we go about building components, but in maintaining a high level of quality across overall user experience. Cross Discipline Approach
At Kanopi we acknowledge that achieving healthy Web Vitals across the board is not siloed to one discipline. Ensuring healthy Web Vitals requires a cross discipline approach spanning Front-end Engineering, Web Engineering, Systems, Audience and Revenue and Visual Design.
As defined by Google, the 3 Core Web Vitals are currently:
Largest Contentful Paint
Largest Contentful Paint is an important metric for measuring perceived user performance, specifically loading performance.
This metric reports the render time of the largest element on the page that is visible to the user.
An LCP score of 2.5 seconds or less is considered to be a conducive measurement for good user experience.
LCP is measured in seconds (s) and can be tracked against the following DOM elements:
An element with a background-image Any element that is considered to be block-level (display: block) How to diagnose Largest Contentful Paint
The quickest way to diagnose the Largest Contentful Paint element on the page is by following these steps:
Select the Performance Tab Check the Web Vitals checkbox Click the Reload button or hit ⌘ ⇧ E shortcut Select the green LCP marker In Summary scroll down to “Related Node” Click the node listed and it will be highlighted in the DOM. How to fix Largest Contentful Paint
Once you have diagnosed which element on the page has the Largest Contentful Paint, the next step is to figure out why.
There are 3 main factors that contribute to LCP:
Slow server response times. Render-blocking JavaScript and CSS. It’s important that your server is optimized in a way that doesn’t have a domino effect on other vitals.
To measure the “speed” of your server you can track the vital. Here are some high-level guidelines for ensuring Largest Contentful Paint occurs as fast as possible:
Serve assets (Images, JavaScript, CSS, Video) over a CDN. Ensure that there is a well-thought out caching strategy in place. Use <link rel="preconnect"> and <link rel="dns-prefetch"> for assets that originate at third-party domains. Ensure that scripts and styles are carefully audited to ensure that there are no render-blocking patterns in order to improve First Contentful Paint, which will consequently improve Largest Contentful Paint. Ensure that your CSS bundles are minified (see ) and deferred if the CSS rules do not apply above the fold. You can also use Chrome’s “Coverage” tab to identify just how much of your CSS bundle is being utilized on the page. Ensure that your JS bundles are minified, compressed and if the functionality is not required above-the-fold, lazy-loaded. The time it takes the browser to fetch resources like images or videos can also have an effect on LCP:
Optimize and compress all images on the site - ensure images are not greater than twice their contained real-estate. Make sure that images are being served over a CDN, you’re serving formats like WebP or AVIF and you’re using responsive images techniques. For images that find themselves in Hero components, preload the image resource ahead of time. For you will need to add the imagesrcset and imagesizes attributes: <link rel="preload" as="image" imagesrcset=" image-400.jpg 400w, image-800.jpg 800w, image-1600.jpg 1600w" imagesizes="100vw" />. Check with Systems or Web Engineering that the server is utilizing compression algorithms like Gzip or Brotli. Cumulative Layout Shift
Cumulative Layout Shift measures the visual stability of a web page.
CLS can be an elusive metric to get right as elements targeted as having a layout shift are often not the root cause. By ensuring
limited layout shifts on the page, visitors will be presented with a smooth and delightful user experience.
A CLS score of 0.1 or less is considered to be a conducive measurement for good user experience.
It’s important to understand that the CLS metric does not just measure one offending element. The CLS score reported is the sum total of all layout shifts on the page. A layout shift occurs any time a visible element (i.e above the fold), changes its position from one rendered frame to the next.
To be clear, a layout shift is only considered a problem if it’s unexpected - so a shift in an elements position that was triggered on purpose by a user is acceptable.
It’s useful to know that a layout shift can be caused by the following events:
A change in the position of a DOM element A change in size of the dimensions of a DOM element Inserting or removing DOM elements through JavaScript CSS / JS animations that would trigger Reflow (recalculation of layout) Considering the above, it would be plausible that nearby DOM elements could then change their position and dimensions based on another elements movement.
How to diagnose Cumulative Layout Shift
The quickest way to diagnose an element that has undergone a layout shift is by following these steps:
Select the Performance Tab Check the Web Vitals checkbox Click the Reload button or hit ⌘ ⇧ E shortcut Scroll down to Experience If there is a Layout Shift on the page, Chrome will add a red bar with “Layout Shift” as the label. In Summary scroll down to the “Moved from” / “Moved to” section. Hover over each “Location” / “Size” label and Chrome will highlight the offending element on the page. As an alternative, you can also diagnose Layout Shifts on the page by:
Hit ⌘ ⇧ P to open the actions console. Start typing “Rendering” until the prompt suggests: “Show Rendering”, hit Enter. A dialog will appear at the bottom of the DevTools window. Check “Layout Shift Regions” and refresh the page. All elements that have been identified as triggering a layout shift will be highlighted. How to fix Cumulative Layout Shift
Elements that cause CLS can be easily fixed in some instances. As a general rule of thumb ensure that:
All images loaded on the site have a width and a height attribute. This is because HTML gets parsed before CSS and the browser will reserve space if it knows the dimensions and aspect-ratio of the image. Ensure that ads, iframes and other embeds have a width and height attribute. As a best practice, do not insert dynamic content into the site without the user performing an action to receive it, ie “load more” or “click”. Ensure that you have a Web Font Loading strategy in place that mitigates layout shift when fonts are loaded and displayed in the browser. When animating CSS properties, ensure that you animate transform properties rather than box-model properties to prevent reflow and layout changes in the browsers Handling Ad Sizes
When it comes to ads, it’s important that slot sizes are consistent in order to prevent CLS. Ads are generally difficult to predict considering that Ad Servers can serve ads at different heights and widths depending on impression data. There are a number of ways to mitigate this:
Speak to Audience and Revenue or your Ad Ops team and see if it’s possible to ensure that ad units are served at more consistent sizes based on impression analytics. If you can achieve more consistent ad sizes, you can reserve space for ad slots by using the min-height CSS property: <div id="ad-slot" style="min-height: 250px;"></div> If you want to dynamically set the height and width of ads once the GPT.js script has ad data you can use the following function: googletag.pubads().addEventListener('slotRenderEnded', function(event) {
var size = event.size;
if(size === null) return;
var slot = event.slot;
var slotDiv = document.getElementById(slot.getSlotElementId());
if (size[0] > slotDiv.clientWidth) {
slotDiv.style.width = size[0] + 'px';
}
if (size[1] > slotDiv.clientHeight) {
slotDiv.style.height = size[1] + 'px';
}
});
A combination of both 2 and 3 has yielded great improvement to CLS scores. Consider using googletag.pubads().collapseEmptyDivs(); to ensure that ad slots that probably won’t fill take up no height and width on the page. Handling Web Fonts
Handling FOUT (Flash of Unstyled Text) and FOIT (Flash of Invisible Text) have become a much discussed topic recently. It’s important to be aware that your page could subscribe to either of the unwanted side-effects of embedding custom fonts. Here’s what you can do to mitigate those effects:
Use font-display: swap if your fonts are hosted locally. Where possible, preload font files using the <link rel="preload"/> schema in conjunction with font-display: optional Where possible, host your fonts locally. Subset your font files if you know that your site will not be translated into other languages. Cache font files on the web server. Use libraries like to asynchronously load fonts on the page. The can be used as an alternative to WebFontLoader if you’re looking for an approach with more control. Ensure that your fallback fonts closely resemble the desired primary font in the stack. A layout shift will / can occur when fallback fonts have different line-heights, kerning and leading. First Input Delay
First Input Delay measures the interactivity of the web page. It quantifies the user’s experience with regards to how fast the page load feels.
By maintaining a low FID score, users will feel like the page is loading faster.
First Input Delay is specifically purposed for measuring how quickly the page becomes interactive to the user on their first impression, where as a vital such as First Contentful Paint measures how quickly the page becomes visible. These are 2 important concepts to grasp when it comes to debugging and diagnosing Core Web Vitals.
An FID score of 100 milliseconds (ms) or less is considering to be a conducive measurement for good user experience.
FID is a unique Core Web Vital and is not actually tracked in Lighthouse or other service metrics. FID is a field metric, meaning that its score is generated by collating data from millions of websites accessed by Google Chrome users. When it comes to generating a score for FID “in the lab” or otherwise through Lighthouse, you will be looking to improve the metric. You can think of TBT as a proxy to FID. This is because FID requires a real user and real users cannot be “spoofed” by Lighthouse. Most importantly, this vital measures the delay from when an event has been received to when the main thread of the browser is idle, this is also known as “input latency”. The “event” can include user events like clicks or taps, but there are far more events in JavaScript that do not require actual user input. FID does not measure the time it takes to actually process the event in JavaScript or the time that it takes to update the UI based on event handlers.
How to diagnose First Input Delay
Unfortunately, diagnosing Total Blocking Time in Chrome is not as easy as diagnosing Largest Contentful Paint or Cumulative Layout Shift.
One of the biggest clues for diagnosing TBT is identifying heavy JavaScript execution on the main thread. This requires an understanding of how the browser parses HTML and JavaScript as well as what is known as a . A Long Task is any JavaScript-based task on the main thread that takes longer than 50 milliseconds (ms) to execute. While the browser is executing a JS task on the main thread, it cannot respond to any user input, as JavaScript is not a multi-threaded language. You can identify any Long Tasks on your webpage by following these steps:
Select the Performance Tab Check the Web Vitals checkbox Click the Reload button or hit ⌘ ⇧ E shortcut If there are Long Task’s recorded during page load, you’ll see a grey bar labelled by “Task” and then a red diagonal pattern overlay. Hovering or clicking on this bar will indicate a long task in the browser’s main thread. In order to better understand and pin-point the offending execution, you can click on “Call Tree”. Once in the “Call Tree” dialog you will see under “Activity” that the length of the task is broken down into function calls and will provide you with a link to the offended JavaScript source file. You can continue your debugging from there. Using Google Chrome’s “Coverage” tab can provide critical insight into how much of the JavaScript on the page is actually being used.
Identifying this code can help you off-load non-critical JavaScript until after page load.
How to fix First Input Delay
FID can be fixed in a number of ways that relate to analyzing JavaScript performance:
Optimizing your web page for interaction readiness Reducing JavaScript execution time. We’ve already discussed at a high-level what Long Tasks are, but more importantly, we want to make sure that these long tasks can be broken up into smaller, asynchronous tasks. This can be achieved by code-splitting your JavaScript bundles using syntax as well as keeping an eye on polyfill’s clogging up your main bundle. Fallback polyfills can add a tremendous amount of bloat to bundle sizes. Other factors to look at are the size of your JavaScript bundles as well as how many JavaScript files your page is loading during initial load. If the main thread has to parse unnecessary JavaScript that may not be needed by the user the chance of Long Tasks preventing user interaction during load rises exponentially. Where possible you should also defer the fetching of data from API services as network latency can also effect TBT.
One area of conversation (especially with clients) should be around the number and purpose of 3rd-party scripts. Multiple 3rd-party scripts can quickly become unmaintainable and lead to delayed JavaScript execution. Ensuring 3rd party scripts use the async and defer attributes can also help improve latency.
Measuring
A plethora of tools have become available to manage and maintain healthy Core Web Vitals. In fact, most performance/reporting based tools now offer some kind of Web Vitals-based data. At Kanopi, we use the following tools to report accurate Web Vital metrics:
This library can be used during development to diagnose Web Vital metrics. It comes with a fairly easy to understand API that directly tracks
Web Vital data on page load. The data can be a bit hard to read but if you’re looking for a programmatic approach to understanding the health
of your web page, this library won’t let you down.
import {getLCP, getFID, getCLS} from 'web-vitals';
getCLS(console.log);