On the 28th of May, 2020, Google announced that, “through both internal studies and industry research, users show they prefer sites with a great page experience.”
Who would’ve thought?
Earlier that month, the Chrome team introduced the Core Web Vitals, “a set of metrics related to speed, responsiveness and visual stability.”
What on earth are they, and why should we care?
One might think that it’s all about User Experience (UX), and that’s because it is. They represent a metric to measure a real user page experience when visiting a website.
There are several web vitals metrics; however, the three core web vitals are: LCP, FID and CLS. Let’s take a brief look at what they are.
LCP: Largest Contentful Paint
LCP measures the loading speed of a website, which should always be 2.5 seconds or less. It measures the largest image or block of text within the viewport window, which is the available visual space in your browser.
FID: First Input Delay
FID measures the time it takes for the website to become interactive once the browser ‘paints’ the website in the viewport. There is nothing more annoying than seeing a button loaded on the page with no response once clicked. This occurs due to the browser still working in the background. A good FID is less than 100ms.
CLS: Cumulative Layout Shift
CLS measures unexpected layout shifts. This measurement is taken over the entire lifespan of the page. Each individual shift is considered to create a sum total, which is where the ‘cumulative’ comes from.
CLS can have all sorts of repercussions. This can be anything from being a simple annoyance to a user by moving content unexpectedly but could potentially result in the user paying thousands of euros by clicking the Confirm button instead of the Cancel button due to unpredictable layout shifts.
OK, now we know what the problem is, what’s the solution?
It’s very simple to explain, but not as easy to execute due to the complexities and sometimes philosophical understandings.
“Why write one line of code when you can write ten?”
In coding, there are things called functions that facilitate the writing of code; be it speed of writing or performing complex sorting calculations, these functions make a developer’s life easier; that’s why they exist.
But since there is no such thing as a free meal, ‘easier’ can come at a cost. These functions are quick to type but can be very CPU or database-intensive. All this can work fine if you receive a few hundred visitors a day, but once you hit a few thousand visitors per hour, you’re in trouble.
In that case, we take these functions apart and write a custom one that is leaner and more optimised to our needs.
We also optimise code in other ways.
First pool, then loop
Let’s say you have 1000 customers in your database and you need their names, address and ID number.
The unoptimized approach:
You ask the database, “Get me all the customers and their name.”
Loop through each customer one by one, requesting their address each time.
Loop through each customer one by one, requesting their ID number each time.
The optimised approach:
You can ask the database, “Get me all the customers, and while you’re there, grab their address and ID number.”
The unoptimized approach would send 2001 hits on the database, while the optimised process would send single database hit. Of course, you will still run a foreach loop for the optimised approach, but at least you’re hitting the database once, not 2000 times. These sort of database operations are very expensive, whereas looping through stuff is a computer’s favourite hobby.
That’s why we adopt a “first pool then loop” philosophy; aggregate the data you need first (pool it), then do whatever you need with it (loop it).
Size matters
Another way we optimize code is by minifying it, i.e. make it physically smaller. We start with writing code that’s readable to humans (some developers are still considered human, anyway). Unminified code is clean to read and legible. It’s also good practice to comment code to make it easier for other developers understand what is going on; however, this increases the bulk and size of the final codebase.
All this makes the file bigger in size, while not making a single difference from a computer-mind point-of-view as extra white spaces and left-indents are ignored anyway. So we minify it – we make it smaller by removing white spaces and left-indents, and if we call a variable (the ‘x’ in “x=1” in algebra) “$matchesByDateWithCherriesOnTop” because it’s easier for us to understand what data is holding, the minifying process will call it ‘e’, or ‘a’, or ‘fs’. In the end, it doesn’t matter; the computer will know. But ‘fs’ is definitely smaller than $matchesByDateThisVariableNameIsTooLong.
OK, so that was all about speed, mostly the LCP part. What about FID?
Better late, than now
One way we deal with First Input Delay issues is by deferring code.
For a website page to work, you don’t need every single line of code to be downloaded and doing its job for the page to work. So we delay the loading of certain code while retaining complete control of how the user experiences the website. Once we know a user is happy with a certain amount of functionality, we then let the rest of the code load in the background.
We make this so smooth, that the user is not aware that this is happening behind the scenes.
Important and urgent vs Important but not urgent
Every single line of code we write is important; otherwise, it’s dead code. But some code is more important than others, particularly when it comes to CSS – the type of code we use to make websites look good.
We extract what’s called the ‘critical CSS’ – that’s the CSS that is used to design the part of the website that’s above the fold. This term that comes from newspaper printing referring to the part of the front page that shows while looking at the newspaper folded in half.
However, when it comes to websites, every page must be considered as a ‘front page’ since a user can land on any one of them, depending on their search criteria. So we go through each type of page, and we have it load the critical CSS first (important and urgent), then the rest of the content (important but not urgent) will load once the “above-the-fold” is looking all nice and neat.
Now press Control-Shift-Layout
As I mentioned earlier, Cumulative Layout Shift can be insidious. There is a misconception that CLS refers to the content that loads late, but it is not so.
If you have an advert that loads 5 seconds after the page seems to have fully loaded (but didn’t), it is not that advert that shifted but the content below it once the advert loaded.
Every little piece of content in a webpage can be said to live in a ‘container’. If the container is empty, it can occupy the full width of the page but have a height of zero. That’s just how browsers behave. Once the advert loads, it can finally take its proper height, so it shifts the content down by the same amount of its intrinsic height.
It’s quite easy to solve this issue, but it’s incredible how many frontend developers neglect to take care of it.
You simply set the height before the content actually loads. Of course, it’s very straightforward for adverts and banners; it’s a little trickier when dealing with actual content that loads a little late.
We deal with that by setting the width and height of every single image that is displayed on the page so that space is reserved for each image. We try to avoid inserting content above already-existing content unless it’s a choice selected by the user. In this case we dynamically reserve the space for the content to be loaded until it finally loads. This way, the user will know what to expect, which makes for a better UX.
This enables us to control the layout shift in predictable ways or, even better, avoid it altogether.
If you behave, I’ll give you a star
Google will also be rolling out a new feature in its SERPs (Search Engine Result Pages) to show users which websites are adhering to the Core Web Vitals metrics they’re implementing and to what level. This means that following the best practices will reward us with better ranking results, and bestow more trustworthiness on our products.
Trust builds a relationship, and a relationship makes for a great, long-lasting business.
Written by: Sammy Hayman