How to make your website go FAST and buttery SMOOTH

Peterkwkwan
CodeX
Published in
5 min readApr 27, 2023

Performance is crucial when it comes to providing a good user experience. In an age of smartphones and speedy internet connections, users have little to no tolerance for a bad UX.

First impressions mean everything, so if your site takes longer than necessary to load, it could mean one less sale or customer for your business.

So how do we obtain that coveted, green, 100% Lighthouse performance score?

Feels good

Lately, I’ve been working on my personal website (still in beta!). I’ve never paid attention to performance since I started the project last year, so naturally, I was curious when I stumbled across the Lighthouse developer tool.

I decided to run a quick test. Below were the results.

Definitely needs work!

Needless to say, I was not happy with these scores! I started digging around to see what was going on under the hood, specifically for performance.

Cumulative Layout Shift (CLS) and Largest Contentful Paint (LCP) were killing me

According to the Lighthouse performance weightings, Cumulative Layout Shift (CLS) and Largest Contentful Paint (LCP) were dragging my performance rating down. What is going on?

Let’s try to improve my site by tackling these two metrics.

Cumulative Layout Shift (CLS)

CLS is a measure of the largest burst of layout shift scores for every unexpected layout shift that occurs during the entire lifespan of a page. These shifts are usually due to font changes, images without dimensions or ads, embeds, and iframes without dimensions.

To figure out which elements where affect the CLS score, I hopped over to the Performance tab. It turns out, it was my title header that was causing the shift.

Found the culprit!

To see the CLS happening in real-time, I slowed down my internet connection in the network tab to “Fast 3G” and reloaded my page. It turns out, the header was using the default system font initially, Times New Roman, but only for a brief second. Then my custom font, League Spartan, kicked in, which resulted in a sudden, split second change in font-family.

I’ve managed to capture the before and after shots thanks to the slower simulated internet speed. Comparison below:

Notice the change in element size from Times New Roman (left) to League Spartan (right)

The change in font was causing an abrupt shift in the element size and surrounding containers. Although the change in size looks relatively minor, it causes a jarring effect for the user.

One way to combat this font-induced layout shift is to use a fallback font. The page will use this fallback font before it has time to properly load your custom font. The strategy here is to minimise the shift by adjusting the size of the fallback font to match the size of the custom font.

The fallback font should utilise a default system font like Arial or Times New Roman. Use CSS properties like size-adjust or ascent-override to appropriately size the fallback font.

/* main.css */

@font-face {
font-family: 'League Spartan';
font-weight: 100 900;
src: url(/assets/fonts/LeagueSpartan-VariableFont_wght.ttf);
font-display: swap;
}

@font-face {
font-family: 'League Spartan-fallback';
size-adjust: 78.5%;
src: local('Arial');
}


/* Home.css */

h1 {
font-family: 'League Spartan', 'League Spartan-fallback';
}

Some meta-frameworks such as Next.js offer automatic font optimisation to combat layout shifts.

Largest Contentful Paint (LCP)

LCP measures when the largest content element in the viewport is rendered to the screen. This approximates when the main content of the page is visible to users. An LCP time of over 4 seconds is considered a poor rating.

As it turns out, my poor LCP score was also related to my title heading with my custom font!

Oops.

Long story short, I had too many custom fonts and large image files affecting my initial page load. I had a two parallax effect screens on the home page, each with 6+ large image files each. On top of that, I had 6 different custom fonts that needed to be loaded. Font files are large and expensive.

To improve my score, I removed one parallax effect screen along with the large image files. I also optimised the remainder of my images using image compression and switching to WEBP image format instead of using JPEG or PNG.

This shaved considerable size off the network payload.

I was 8 times over Google’s recommended total byte size of 1,600 KiB

If your site has a high network payload, it may make sense to split up your resource load times with lazy loading, or remove some nice-but-not-essential, expensive assets. Switching to a CDN or caching assets is also an effective way to improve initial and subsequent renders.

Further Optimisations

Sometimes, external libraries may not be the ideal solution for your site. For example, I ended up removing my DateTime library and replacing it with lightweight, self-written solutions.

Libraries containing CSS effects and custom components are oftentimes bloated. Try researching a few solutions online or ask ChatGPT to help come up with an appropriate workaround. Consider the tradeoffs when adding dependencies, as minimising the JavaScript bundle size is one of the easiest ways to improve performance.

My site is far from complete, and I hope to further optimise it by switching over to a CDN provider for my assets. Migrating to a Static Site Generation framework like Next.js will also be beneficial by fetching my content at build time using getStaticProps instead of relying on client-side data-fetching.

If you have any essential performance tips & tricks, please comment below! I’d love to hear from you.

--

--

Peterkwkwan
CodeX
Writer for

Hey! I'm a self-taught developer with over 4 years of frontend experience. I enjoy writing about tech, frontend tools and software engineering as a career.