Vital Web Performance

By  on  

I hate slow websites. They are annoying to use and frustrating to work on. But what does it mean to be “slow”? It used to be waiting for document load. Then waiting for page ready. But with so many asynchronous patterns in use today, how do we even define what “slow” is?

The W3C has been working on this with the new Event Timing and Element Timing API, and has defined some new Web Vital metrics to describe the different ways that slow performance can impact a webpage. Google is even going to use these web vital metrics as a search ranking factor!

Let’s have a look at them, and how we can apply them to keep our site fast and our pages well-ranked.

1. Largest Contentful Paint (LCP)

Some websites look like they loaded fast, but all the meaningful content is still waiting to be loaded. This pattern made the page load performance numbers look great, but the user still feels like the site is slow.

Largest Contentful Paint (LCP) is the time since a page was started that the largest block of meaningful content was loaded. Largest is measured in the pixel dimension of the element, so it could be anything that takes up a lot of space in your UI. This could be a big image, block of text, or a really annoying advertisement.

Web pages that only show the UI “frame” in the main document and load the content asynchronously will have poor LCP scores. Fun fact, we recently audited the web performance of Google search and they inline nearly all the content in the original document!

Learn more about the Largest Contentful Paint

2. Cumulative Layout Shift (CLS)

Janky web pages that keep shifting around, drawing new content, and pushing down the things you were trying to read, have lots of Layout Shift. Layout Shift happens whenever new elements added to the page move the placement of other elements. Like an advertisement rendering on top of that paragraph you wanted to read should have been. Looking at you The New York Times.

Cumulative Layout Shift (CLS) is the sum of all the layout shifts that happen on a page. When there is a lot of asynchronous content, there are lots of layout shifts and the CLS is high.

This generally happens when large portions of a webpage’s content are loaded asynchronously into the document by an AJAX call and client-side rendering. Third-party advertising is the classic offender.

Learn more about the Cumulative Layout Shift.

3. First Input Delay (FID)

Web pages that load obnoxious amounts of JavaScript, tracking pixels, and asset dependencies are asking the browser to do a lot. Each of these assets has to be discovered, downloaded, parsed, and applied—and that’s a lot of work! If the browser is busy doing this work when the user first tries to use your page, it feels slow.

First Input Delay (FID) is how long the page is busy when the user tries to interact with the page for the first time. This isn’t a measure of event handler code, it’s the time the browser delays handling the event because it’s busy. If the browser is busy parsing lots of JavaScript when the user tries to click a button, then there is a large FID.

Developers often solve this problem with a loading screen, which delays the first input rather than solving the problem: loading too many things!

Learn more about the First Input Delay

Measuring Your Web Vitals

Now that we know the concept behind these vital metrics, how do we measure them? They are all based on the draft spec for Element Timing API, which is not yet well adopted. Chrome (and other Blink-based browsers) support this today, so you can start capturing these metrics for some of your users.

try {
    new PerformanceObserver(entryList => {
      entryList.getEntries().forEach(console.log)
    }).observe({ type: "layout-shift", buffered: true });

    new PerformanceObserver(entryList => {
      entryList.getEntries().forEach(console.log)
    }).observe({ type: "largest-contentful-paint", buffered: true });

    new PerformanceObserver(entryList => {
      entryList.getEntries().forEach(console.log)
    }).observe({ type: "first-input", buffered: true });
}
catch(e) { /* API is not supported */ }

Measuring each of these types has its own gotchas and special conditions. For example, to handle ”layout-shift”, we need to sum every value that we receive because we are measuring the cumulative layout shift. We should also consider whether the layout shift was caused by a user input, which is one of the custom properties attached to this entry.

let cumulativeLayoutShift = 0;
function handleLayoutShift(entry) {
  if (!entry.hadRecentInput) {
    cumulativeLayoutShift += entry.value;
  }
}

The links above cover the various implementations and requirements for each metric. You’ll need to decide how you want to capture and save these metrics, as well as reporting on them.

Or Request Metrics can do it for you! Request Metrics is the fastest, simplest, and cheapest way to understand real user web performance. It can capture these metrics, along with a bunch of other useful data, and distill it down to what’s really important. All for just $10/mo.

It’s way easier than chasing these moving APIs yourself.

Let’s go fast.

Todd Gardner

About Todd Gardner

Todd Gardner is a software entrepreneur and developer who has built multiple profitable products. He pushes for simple tools, maintainable software, and balancing complexity with risk. He is the cofounder of TrackJS and Request Metrics, where he helps thousands of developers build faster and more reliable websites. He also produces the PubConf software comedy show.

Recent Features

  • By
    9 Mind-Blowing WebGL Demos

    As much as developers now loathe Flash, we're still playing a bit of catch up to natively duplicate the animation capabilities that Adobe's old technology provided us.  Of course we have canvas, an awesome technology, one which I highlighted 9 mind-blowing demos.  Another technology available...

  • By
    CSS Filters

    CSS filter support recently landed within WebKit nightlies. CSS filters provide a method for modifying the rendering of a basic DOM element, image, or video. CSS filters allow for blurring, warping, and modifying the color intensity of elements. Let's have...

Incredible Demos

  • By
    GitHub-Style Sliding Links

    GitHub seems to change a lot but not really change at all, if that makes any sense; the updates come often but are always fairly small. I spotted one of the most recent updates on the pull request page. Links to long branch...

  • By
    Translate Content with the Google Translate API and JavaScript

    Note:  For this tutorial, I'm using version1 of the Google Translate API.  A newer REST-based version is available. In an ideal world, all websites would have a feature that allowed the user to translate a website into their native language (or even more ideally, translation would be...

Discussion

    Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!