[MUSIC PLAYING] PATRICK KETTNER: So you know that thing when you start to read a website when all of a sudden, the page just kind of jumps like hundreds or thousands of pixels, and you have no idea where you were? Or when you go to tap on a button, and the button just has a popup that pops up right where your finger is, leaving you desperately smashing that back button? Well, these things are called layout shifts.
And layout shifts like this are terrible. But with the metrics that make up page experience, it's finally a lot easier to make these lamentable layouts less shifty and more nifty. Stick around as we check out yet another one of these metrics, Cumulative Layout Shift.
When we're talking about Cumulative Layout Shift, or CLS, if you're as easily tongue-tied as I am, what we're talking about is how stable a page is-- or rather, how predictable a page is to use. All the visible parts of a page and how they fit together make up what a browser thinks of as a layout-- images, text, video, all of it. Now sometimes when the contents of a page changes, like when an ad is inserted, a widget loads, or an image changes size, stuff that's already visible on the page can end up needing to be shifted around for everything to fit.
Every time that happens, well, that's a layout shift. Cumulative Layout Shift is a way to look at how much-- as in what percentage-- of the visible parts of a page experience these layout shifts. For example, here we have a simple blog article.
There's a headline, a hero image, and text. On a slower connection, the text shows up right away. But the image takes a bit more time to appear.
Eventually, the image will be downloaded. But before those pictures' pixels can be painted, some changes might need to occur. See, as far as the browser is concerned, everything above the image is fine.
Nothing needs to change. But in order for the image to show up where and how it was intended, everything below it has to shift down to make room for it. So the text of the article gets pushed down half the visible amount of the page in order to make room for the image.
That means 50% of what we can see has to be shifted just for the image to show up. That will give us a CLS of 0. 5, as in 50%.
So a page's CLS score is basically how much the visual parts of a page change. There is a few caveats to this, however. Number 1, there can only be one.
Earlier we said that our page had a CLS of 0. 5. That's true, but only if nothing else ever shifts on the page.
Or at least if I exit the page before anything else shifts. If, however, later on, an ad loads and shoves everything down, our CLS could shoot way up. In this case, literally everything has moved.
That means our class is now 1. Every time someone visits the site, the browser will continually track CLS for the entire time that they use it. Once they navigate away or close the tab, the browser will report the largest CLS value found.
That one number gets collected with all the other visitors to that URL and generates the CLS value for that page's web vitals. Number 2. Sometimes, change is a good thing.
If pages never changed, they wouldn't be that useful. And CLS certainly wouldn't want that to happen. Layout shifts that are triggered by user interactions-- things like tapping, clicking, or typing-- are given a 500-millisecond grace period to perform any layout shifts they need to best respond to that user.
After those 500 milliseconds, a new CLS session window starts. From millisecond 501 onward, any content shift that occurs gets added up and potentially used for a final CLS score. That session window will stay open for as long as there are visible layouts being shifted.
Any additional shifts are added together. For example, another page on our site has a similar layout-- a headline and body text. This time it has two smaller images.
Just like before, they're slow to load. So our content shifts once they do. Unlike before, the first image only shifts a small amount-- 5%.
So now our CLS would be 0. 05. But then the second image loads several hundred milliseconds later.
It also needs a little bit of room, so the contents get pushed down even further. It shifts the visible amount 2. 5%.
Since it happened so close to the last layout shifts, they are accumulated into one single value-- 7. 5% or 0. 075.
The session window will stay open until more than one second has passed since the last layout shift, or until five seconds have passed since the creation of this session window. Any future layout shift gets counted as a separate layout shift event and not added to the previous window. Number 3.
Not all interactions are free. User interactions like scroll or mouse move don't count as the kind of events that give you that 500-millisecond grace period. Well, this makes sense.
I don't think a user would really expect the layout of a page to shift while they were scrolling. Number 4. Not all changes are bad.
You can actually move content on the page all you want via CSS animations and transforms. This is because when you set a CSS attribute like transform, the element gets moved to its own layer. This means that its position isn't impacting the layout of any other part of the page.
It's like floating on top of everything else. And since nothing else is being shifted, it won't count towards your CLS. Finally, number 5.
What you can't see can't hurt you. You may have noticed that I've repeatedly emphasized that CLS is only for the visible elements of the page. That's because as far as CLS is concerned, if you can't see it, it doesn't matter if it's moving.
Like all page experience, CLS is about making sure that people have the best user experience possible. So if you need to move something around or lazy load in content, go for it. If it isn't visible to the user or shifting what is visible to the user, then your CLS will not be affected.
The key thing to remember is that a good CLS score means that what your user sees is stable and predictable. It's not jumping all around. So now we know what CLS is and that it's represented by a number between 0 and 1.
But what should that value be? In a perfect world, 0. I mean, there's almost never a need for a layout shift to occur.
We can almost always prevent them. And in fact, we're going to get into specifics of just how you can do that real soon. In the real world, though, we all have jobs.
And our sites are really bouncing tons of different concerns. So if you can't hit 0, then a great number to aim for is 75% or more of the views a page has, has a CLS of 0. 1 or less.
If you're below that, you're doing great. But anything above it, well, stick around, and we'll see if we can lower it. [EXHALATION] I know that was a ton of information, but I promise, now you know it all.
I mean, that's what CLS is. It's great to get that taken care of. But now you may be asking, well, how do I figure out what my CLS score is?
Well, like all the Core Web Vitals, CLS is what actual users are experiencing when using your site. We call this information field data. As a result, you can only really actually rely on the user measurements that come from those real world users either via your own analytics or the ones you have access to inside of the Core Web Vitals report section of the Search Console.
If you haven't already, you will need to create a Search Console account. But I highly recommend it. See, you'll have some invaluable information in there to how your page is performing with page experience as well as many other foundational pieces to an outstanding fantastic modern website.
Search Console, page experience, and Core Web Vitals all have the same source for your page's CLS result-- CrUX, or the Chrome User Experience Report. You can read all about what CrUX is in the links below. Unfortunately, CrUX doesn't update instantly.
It can take up to a month after you publish your page for it to start getting field data. But you don't need to wait that long to get an idea of how the page you're currently working on will perform with CLS. Using tools like Lighthouse, available in the links below as well as directly in your Chrome DevTools, you can quickly get the same field data we have in Search Console for any page, as well as generate lab data.
Lab data is a best guess effort as far as what field data will likely look like. It's based around average mobile devices and average mobile internet speeds. Keep in mind, however, that lab data is a guess.
It can be helpful to point you in the right direction. But field data is the only value that page experience, and therefore search, is going to actually look at. If your users have high end devices or unusually slow connections, you are more likely to see a larger difference between lab and field data values.
Lab data can be really helpful. But once you actually publish your page, I think it's a bit more useful to actually collect CLS data via our own analytics. Just like the other Core Web Vitals we discussed in the previous episodes, we can measure CLS with our own JavaScript using a performance observer.
This is a relatively new browser API that lets us subscribe to events that happen in the browser related to performance. We don't have the ability to directly observe the cumulative layout shift value, but we do have all the right pieces we need to figure it out for ourselves. In this case, we're going to be subscribed to the layout shift performance event.
Now every time the browser has a layout shift event, our code gets called. We can use all the information here to figure out what the CLS is going to look like for this user. Once our function is called, it gets an entry list of every layout shift that has been observed.
We can call Get Entries on this entry list to get an array of entries so that we can iterate over each individual one. From there, we can check if an entry had a recent input. It's a handy property provided by the browser on every layout shift entry.
If "had a recent input" is true, then we are in that first 500-millisecond grace window and can just ignore this entry. But if "has reset input" is false, then we can grab entry. value and add that to our CLS.
Now, you may have noticed that this counter just keeps getting added to. Didn't we talk about session windows earlier? Well, you eagle-eyed straw man, you're right.
In fact, this is how CLS was originally calculated. It's the sum of the entire session of a page. But based on feedback and continued research, CLS was evolved to use the session window methodology we discussed earlier.
You can read more about it in the links below. So if you wanted to track the CLS value that matches the same logic that exists today, we can update our code to track it with just a few more variables. In the interest of time, there's a link to the updated version of that code in the description below if you're interested in seeing how the specifics of the tracking session window would work.
Now that we know how to collect the CLS value, we still need to trigger an analytics event. The specifics of how we will actually go about doing that are going to be purely on your own infrastructure. But the specifics of when we do it is a lot easier to cover.
The browser has another event called visibility change. This is triggered whenever a page's visibility changes, like when it's minimized, closed, or navigated away from. We can use this event to expand our code to include reporting.
We listen to the visibility change event. And if the visibility state is hidden, then we will call take records on our performance observer. This will give us a list of any entries that haven't been processed by our code already.
We can then process each entry just like we would normally. And then we call sendCLSToTheServer. This is a completely made up function that you'll need to implement in order to work on your site.
If you have any questions about this, please leave comments in the section below. I'd be more than happy to help anybody implement this on their site today. The only oddity left with our code is that in order to make sure that CLS is always being sent when folks leave the page, we're using the visibility change event.
See, it's great to get the right information, but it does come at the cost of multiple analytics events potentially being sent for the same user. If someone has our page open, but then switches tabs, and switches back, and then again, and again, and again, well, multiple events will be sent to the server every single time that switch happens. We'll need to filter these values on the back end in order to get the largest value for each user session.
Remember, there can only be one CLS value. For more in-depth information about how this is accomplished, you should definitely be checking out the wonderful WebVitals. js Library.
It's linked in the description below. It was written by the Chrome team's Phil Walton. It wraps up the complexities of tracking and reporting Core Web Vitals.
And it's a great source if you aren't already familiar with it. So we know what CLS is, what it should be, how to measure it, how to track it, and well, if you're already at or below 0. 1 as a goal, then you're good to go.
Send me a message so I can personally congratulate you. But if you still want to hang around for a bit, I promise you that we'd get into the good stuff-- how to improve the cumulative layout shift scores. Well, let's get to it.
Specifically, all layout shifts can be traced back to really a handful of causes. These include images that don't have inline dimensions, iframes or embeds that don't have inline dimensions, dynamically injected content that doesn't preserve space with explicit dimensions. Are you seeing a pattern here?
And finally, web fonts or icon fonts that cause a flash of unstyled or invisible text. Let's start with probably the most common issue that I've seen-- images. If you recall the example we looked at earlier, an image that didn't include a width or height attribute, either inline or with its own CSS, well, that should actually just be a placeholder note.
It's something that's completely different than the size it will eventually be when it loads. And just like in this example, this causes the content to jump, triggering a layout shift. Luckily, this is a really straightforward fix.
The best, most modern way to address this is to explicitly include the height and weight attributes on our image. These attributes have existed for decades and used to be common practice. But with responsive design and high definition screens, setting these values was often less useful than using CSS or just letting the browser kind of figure it out by itself.
Nowadays, all modern browsers are automatically sizing based off of the aspect ratio, as in how wide an image is divided by how tall it is based on the width and height values. That means that we can still style the image using responsive values like width 100% in our CSS. But browsers will now also automatically reserve the correct height based off of the aspect ratio of the width and height that we provide.
It's the best of both worlds. But perhaps even best of all is that this will prevent these images from triggering CLS. You see no layouts being shifted, even if the image loads on a slower connection.
Next up is iframes and embeds. This can mean a lot of different things-- ad slots, widgets for a video player-- just about anything that we load from another domain or another service-- is likely to be loaded inside of an iframe or an embed. We can't control what happens inside the iframe, but we can control what happens around it.
Just like our images, we need to reserve a space that's going to be taken up by the iframe. By setting explicit heights and widths for the iframe's parent element, the browser is reserving space for it, thereby preventing any kind of layout shift. Now occasionally, the ad network that we may be getting our ads from is not quite serving us the right size for its slot.
It might be a couple of pixels too big. I like to explicitly set Overflow Hidden on those iframe parent containers to ensure that they're not going to be overflowing into anything I'm not expecting. This isn't always practical, though.
Sometimes you need to ensure that every single pixel of an ad is visible. If that's the case, we're going to want to oversize that parent container ad slot and make sure that we modify our design to account for this and make sure it still looks OK even if it's a bit bigger. On the other side, you're going to want to avoid collapsing ad slots when no ad is returned.
See, removing all that space is going to cause just as much of a layout shift as well. You're likely noticing that this is all about isolating iframes and embeds so that they don't take up space that isn't accounted for in our design. So whether we're going to be clipping unexpected content or just overestimating the size to be sure that all of it shows, there's almost always a way to avoid layout shifts with dynamically loaded content.
Not all dynamically little content is in iframes, though. If your site has an infinite scrolling list of articles or product pages, or if you're just doing any kind of lazy loaded content, you will want to make sure that you reserve the space that it's going to take up with an explicit height and width. Just like with iframes, the server is going to hopefully be returning something that will be these dimensions.
But ideally, our pages are designed in a way to be flexible enough to allow for content that's bigger or smaller than expected. As you may have noticed, having a flexible but unchanging width and height on our page's remote resources is key to a rock bottom CLS score. But there's one more still common issue that we should look at.
Up until now, all of our examples can more or less be summed up as, make sure all the rectangles have explicit sizes that don't change. But what do we do if it's the content inside those rectangles that change? This is why web fonts pose a unique challenge to CLS.
We can't explicitly set a width or height on text. And so with a web font or icon font that's causing a layout shift, we'll need to approach it from a different angle. The simplest solution is, don't use the font.
In the case of icon fonts, it's actually just much better to use SVGs directly today. Not only do you get a greatly enhanced design capability, there's going to be much fewer issues that are prone to icon fonts in modern browsers. And it's substantially better for accessibility, too.
But if a web font is causing the shift, and we definitely want to use it, then we need to optimize how the font is being loaded. I'll include some articles about optimizing web font loading and general font best practices in the links below if you really want to go deep on the topic. But a great place to get started is to ensure that any fonts that we are definitely using are going to be preloaded.
Normally, web fonts are going to be lazy loaded, meaning that the browser downloads the HTML, any JavaScript, and the CSS before it starts to download and process any font face declaration we declare inside of that CSS. Link rel preload is a sort of hint we can give to the browser so it can start downloading the font before it discovers it the normal way. That means that it will be ready much faster when it is discovered.
We want to make sure that we put these essential fonts as close to the top of the page's head as possible to give the browser as much time as possible. If the web font is more of a "nice to have," another choice would be to use font display optional. Font display is a property we can set in a font face declaration.
It supports a few different values. And the one that we're using here is telling the browser that the font is, well, optional. When we use font display optional, if the web font takes longer than three seconds to load, the browser will just give up trying to load it.
And whatever is already being rendered is what's going to be shown. So no more changes, no more content shift. When we're already looking at a font-based code, we want to make sure that we aren't already using font display swap.
That more or less does the opposite of optional. Font display swap tells the browser to show whatever fallback font exists right away and then swap it out for the font that we're requesting as soon as it finishes downloading, no matter how long it takes to download. If you use a web font that's slow to load on a substantial part of your page, well, you can imagine how large your CLS score can end up being if you use font display swap.
If you want to have the best of both worlds, I think the last bit of advice I could suggest is to check out the amazing font style matcher included in the links below. This site let you take two different fonts and adjust various CSS properties on each one so that they more or less visually align. Once you have a website font that is close enough as a fallback, you can copy the CSS directly and enjoy that shiftless free page experience.
And that's page experience, folks. We've covered the what, the when, and done deep dives on each part of it. If you didn't see those videos, I'll make sure to include them in a full playlist of this series in the description below.
I know that there's been a lot to this. And I can't tell you how much I appreciate you coming along for the ride. I hope that you've been able to pick up a few things you can use to push your sites that much further.
If you have any questions, please leave them in the comments below or reach out to us directly on Twitter. I look forward to hearing about everything that y'all build. So once again, thanks and see you soon.