Making Nintendo's homepage twice as fast

All the things I did to make Nintendo's homepage load in half the time.

A little while ago I wrote a post about speeding up the landing page for Tesla's Cybertruck, inspired by Jake Archibald's performance reviews of F1 sites. Looking at the things that are slowing down a page can be a useful way of learning what to avoid, and can teach you how to improve those things.

This time, I wanted to see if I could improve site speed for the supplier of everyone's favourite childhood memories: Nintendo.

I did this on a test build of their site where I cloned the HTML - they're (sadly) not a client and I don't work for them.

One disclaimer before I dive in. There are lots of reasons for why sites might not be perfect - often the developers who work on the site are aware, but there might be lots of reasons for why they don't have the time or resources to work on fixing them. This isn't an attack on anyone, no site is perfect - this is purely to explore how a page could be sped up.

What we're trying to improve

The highlighted image below is the Largest Contentful Paint element (or at least, it is for the viewport of an iPhone 11 - and probably most mobile devices), so that's what I'm going to focus on. That said, I also want to improve the time it takes for the page to start rendering.

Don't lazy load above-the-fold images

Nintendo lazy load their images, so the browser only requests them just before they scroll into view. Lazy loading is great for images that are below the fold, but our goal is to have the above-the-fold images render as quickly as possible.

The way that lazy loading has been implemented is also quite a big reason for the slow rendering of the LCP image. There's a JavaScript function for detecting when an image is either in the viewport or about to scroll into it, at which point it then swaps out a grey placeholder image for the real image.

But this means that images that use this lazy loading method don't start being requested and rendered until all of that JavaScript has loaded, which slows them down considerably here.

I fixed this in my test build of Nintendo's homepage by removing the JavaScript method for loading images, and instead used normal <img> tags for the above-the-fold images, which meant the browser was able to see and request those images much earlier.

Remove the anti-flicker snippet

The Nintendo homepage uses an anti-flicker snippet, which was delaying rendering. These are usually in place for when a site is running A/B tests - users might see the control headline, or call-to-action, or whatever it is that's being tested swap from the control to the variant. A/B software sometimes suggests an anti-flicker snippet to solve this problem: it shows a blank white page until the A/B test has loaded, or 4 seconds have passed - whichever comes soonest.

But that's quite a brutal way to solve that problem, especially because Google recommends having your LCP element render in under 2.5 seconds. I solved this by deleting that anti-flicker snippet. I found removing the snippet led to a noticeable improvement in the time it takes for the page to start rendering, particularly on a slow connection.

Remove the legacy Typekit CSS request

I noticed there was a CSS request in the <head> for a Typekit resource, which then itself loads another CSS file. This is render blocking, so the browser has to wait until it's downloaded both files before it starts painting anything to the screen.

We can see this from a WebPageTest waterfall - there are two render-blocking Typekit requests, one after the other.

This could definitely be improved, but I noticed that the page doesn't seem to be using any font files from Typekit anyway, so this was a pretty easy fix: I removed the Typekit request. I suspect this is a legacy thing - the site may have used Typekit on an earlier version, and they seem to now have switched instead to Google Fonts (more on this later).

Alternatively, they might still use Typekit elsewhere on the site - in which case, they could instead look to only include the Typekit request on those pages that use it.

Don't use @import in CSS

There's a couple of examples where a render-blocking CSS file uses @import to load in another CSS file. As an example, this CSS file has an @import for a Google Fonts CSS file.

This is slow because it means those render-blocking CSS requests occur sequentially, when you really want all of your CSS to load in parallel as much as possible.

We can see from the waterfall that the Google Fonts CSS file is only requested after the bootstrap_rd.css file has been downloaded and parsed.

I always recommend avoiding using @import - you can have that CSS load in parallel by using a regular <link rel="stylesheet"> tag in the initial HTML instead.

And while we're at it, self-host those Google Font files

I love Google Fonts for the speed at which it lets you try out different fonts, and it's great for development, but the Google Fonts CDN comes with a performance cost. When you request the CSS from their server, the browser has to spend time setting up a new DNS/SSL connection to the domain, and then again to the domain.

This setup time can take anywhere from 100ms to (on slow connections) more than a second. When we tested it, we found that using the Google Fonts CDN could slow down Largest Contentful Paint by 1.3 seconds on a 3G connection. Instead I recommend self-hosting your Google Fonts.

Compress images and use WebP

Some of the images on the page had a pretty large file size, in particular the first two that appear above-the-fold on a mobile viewport. The main above-the-fold image weighed 182kb, and the image below it was 235kb. That's a little on the high side, so I ran them through Squoosh and converted the JPGs to WebPs which brought the file sizes down to a more reasonable 71kb and 85kb.

Lazy load the images in the side panel

Nintendo's homepage on desktop has a side panel featuring some upcoming games, along with several thumbnail images.

These thumbnail images are shown very far down the page on mobile, so they'd benefit a lot from being lazy loaded. They don't seem to make use of the JavaScript lazy loading method, which is why the browser tries to load them during the initial page load.

In my test build, I fixed this by adding the loading="lazy" attribute to the <img> tags.

Defer the script tags at the bottom of the page

This likely has quite a small impact here - but there were a few <script> tags at the bottom of the page. I suspected that these didn't need to load very early, but I could see from a WebPageTest waterfall that they were loading in earlier than the above-the-fold images (which might also be down to the JavaScript lazy loading library).

I added the defer attribute to the <script> tags at the bottom of the page, largely because they were parser blocking, and I wanted to see if I could get the browser to prioritise loading some of the other, more important resources. Nothing seemed to break, but this is the sort of change that really needs a dev team who understands the codebase to test it thoroughly.

Preload the LCP image

And finally, because I really wanted the browser to load the LCP image early, I added it as a <preload>. This isn't always the right call, and I tend to recommend being cautious with preloading resources, but I found that the LCP image was sometimes fighting for bandwidth with some of the fonts and some of the lower priority JavaScript, and preloading helped to improve that.

Nintendo serve images with different dimensions depending on the screen size (which is good!), so for them to fully adopt preloading images here, they could use media queries in order to preload the correct size. You can find out more about preloading responsive images here.

What's the result?

Here's what it looks like when testing an unaltered copy of the Nintendo homepage compared to a version where I've made the above changes (on a 3G connection, using an emulated iPhone 8).

The improved page starts rendering and is visually complete in half the time. And importantly, these changes resulted in a Largest Contentful Paint improvement of 58%.

September 2021


Thanks for reading. If you found this interesting, you might also like Blackbird - site speed monitoring for ecommerce. Try it for free today.