[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.
[MUSIC PLAYING]