10 Web Performance quick wins 🚄 you can apply in under 5 minutes ⏲️
Published: 2020-08-22 17:39:08

Optimizing the performance of your website takes time, and If you want to work on it towards your individual needs, it can be much work.

I haven't seen any case in my career where it wasn't worth it, but you still need to have the time and money to do these optimizations. Fortunately, Web Performance has some quick-wins. Quick-wins are little changes you can apply in under 5 minutes to your website.

---

If you like this article, smile for a moment, please share it, follow me and [subscribe to my newsletter](https://marcradziwill.com/newsletter/).

---

## Tldr;

In this post, I show you 10 Web Performance quick-wins you can (and should) apply to your site in under 5 minutes. These quick-wins can be little changes to your code-base or your server configuration.

## Why should you apply them

First, it takes maximum 50 minutes to apply these changes, but furthermore, even if you do not get a huge performance boost in your measurements, I would consider these quick-wins as Web Performance best practices. They are simple and easy to implement, don't require a detailed understanding of the part they are applied to and can have a significant impact on your performance.

## Web Performance quick-wins

### 1. Use text compression

With text compression, you minimize the number of bytes that are transferred over the network. There are several compression algorithms. [Gzip](https://www.youtube.com/watch?v=whGwm0Lky2s&feature=youtu.be&t=14m11s) is the most popular, but with [Brotli](https://opensource.googleblog.com/2015/09/introducing-brotli-new-compression.html) there is a newer and even better compression algorithm you can use. If you want to check if your server supports Brotli, you can use the [Brotli.pro](https://www.brotli.pro/) tool.

If your server does not support Brotli, you can install it with the following straightforward guides:

- [Nginx on Linux](https://computingforgeeks.com/how-to-enable-gzip-brotli-compression-for-nginx-on-linux/)
- [Apache](https://bash-prompt.net/guides/apache-brotoli/)
- [NodeJs - Express](https://web.dev/codelab-text-compression-brotli/)

Probably this is the first quick-win you get for free because most of the hosting platforms or CDN provider either compress assets by default or allow you to configure them.

### 2. Image compression

Uncompressed images are a huge potential performance bottleneck. If you do not compress your images before serving them to the user, you transfer unnecessary bytes through the wire. There are several useful tools you can use to compress your images in a fast way without losing visible quality. For my pictures, I use [Imagemin](https://github.com/imagemin/imagemin). It supports many image formats, and you can use it as a [comand line interface](https://github.com/imagemin/imagemin-cli) or as an [npm module](https://www.npmjs.com/package/imagemin).

```bash
imagemin img/* --out-dir=dist/images
```

You can implement the npm module into your bundler like webpack, gulp or grunt. With `imagemin-mozjpeg` you compress your JPEG images to a quality of 60%: The range goes from 0 being the worst and 100 the best.

```js
const imagemin = require('imagemin');
const imageminMozjpeg = require('imagemin-mozjpeg');

(async() => {
  const files = await imagemin(
      ['img/*.jpg'],
      {
        destination: 'dist/img',
        plugins: [
          imageminMozjpeg({quality: 60}),
        ]
      }
  );
  console.log(files);
})();
```

In my case, it reduces the file size from 4MB to 100kB. Check out the working demo code in my [Github repository](https://github.com/marcradziwill/web-performance-quick-wins-tutorial).

| unit |  file size without compression  | file size with compression  | filesize decrease in % |
| --------- | :-----: |  :-----: | -----------: |
| Bytes | 4156855 Bytes | 103273 Bytes | -97% |
| MB/kB | 4MB | 103 kB | -97% |


### 3. Image format

Use modern image formats can give you a real boost for your performance. WebP images are smaller than JPEG and PNG, usually by about 25% - 35%. WebP has a [wide support](https://caniuse.com/#feat=webp) by browsers. Even though all browsers do not support it, it is worth implementing this quick-win.

We use the imagemin npm package an add the [WebP plugin](https://www.npmjs.com/package/imagemin-webp) for it. The following code outputs the WebP version of my image into the dist folder.

```js
const imagemin = require('imagemin');
const imageminWebp = require('imagemin-webp');

(async() => {
  const files = await imagemin(
      ['img/*.jpg'],
      {
        destination: 'dist/img',
        plugins: [
          imageminWebp({quality: 50})
        ]
      }
  );
  console.log(files);
})();
```

Let's have a look at the filesizes again:

| unit |  file size without compression  | file size with compression  | filesize decrease in % |
| --------- | :-----: |  :-----: | -----------: |
| Bytes | 4156855 Bytes | 58940 Bytes | -98% |
| MB/kB | 4MB | 59 kB | -98% |

The results speak for themselves the file size decrease compared to the original image is 98%, and compared to the compressed JPG file, it is even more visible how good WebP compress your images. The WebP version is 43% smaller than the compressed JPEG version.

### 4. Image lazy-loading

Lazy-loading images is a technique to load offscreen images later and not in advance. Images that are loaded right when the parser encounters them slow down the initial page load. With lazy-loading, you can speed up this process and load images later. You can do this easily with [lazysizes](https://github.com/aFarkas/lazysizes). With the lazysizes script and the [native browser support](https://caniuse.com/#feat=loading-lazy-attr) for the loading attribute, you can change your images from:

```html
<img src="image.jpg" alt="">
```

to:

```html
<img data-src="image.jpg" class="lazyload" alt="">
```

The library takes care of the rest, and you can verify this with your browser. Open your site and locate your image tag. If the class changed from `lazyload` to `lazyloaded` it works. Furthermore, you can check the Lighthouse audit for "Defer offscreen images".


### 5. Cache your assets / HTTP Cache headers

Caching is one method of how you can quickly improve your sites speed. It reduces the page load time for returning visitors. You can tell the browser cache files for a specific time. If you have access to your server caching is simple and straightforward to apply.

You can use the following API for caching:

- [Cache-Control](https://developer.mozilla.org/de/docs/Web/HTTP/Headers/Cache-Control#Browser_compatibility)
- [ETag](https://developer.mozilla.org/docs/Web/HTTP/Headers/ETag#Browser_compatibility)
- [Last-Modified](https://developer.mozilla.org/docs/Web/HTTP/Headers/Last-Modified#Browser_compatibility)

### 6. Inline your critical CSS - defer uncritical CSS

CSS is render-blocking. That means the browser must download and process all CSS files before it can paint a pixel. By inlining your critical CSS, you can speed up this process dramatically. You do this by defining your critical CSS. The critical CSS are all styles above-the-fold, so all content in the user's viewport.

You do this with the following steps:

#### Identify your critical CSS

If you do not know what your critical CSS is you can use [Critcal](https://github.com/addyosmani/critical), [CriticalCSS](https://github.com/filamentgroup/criticalCSS) or [Penthouse](https://github.com/pocketjoso/penthouse). All these libraries extract the CSS from your HTML files that are visible in the given viewport.

See the working example of criticalCSS.

```js
var criticalcss = require("criticalcss");

var request = require('request');
var path = require( 'path' );
var criticalcss = require("criticalcss");
var fs = require('fs');
var tmpDir = require('os').tmpdir();

var cssUrl = 'https://web.dev/app.css';
var cssPath = path.join( tmpDir, 'app.css' );
request(cssUrl).pipe(fs.createWriteStream(cssPath)).on('close', function() {
  criticalcss.getRules(cssPath, function(err, output) {
    if (err) {
      throw new Error(err);
    } else {
      criticalcss.findCritical("https://web.dev/", { rules: JSON.parse(output) }, function(err, output) {
        if (err) {
          throw new Error(err);
        } else {
          console.log(output);
          // save this to a file for step 2
        }
      });
    }
  });
});
```

#### Inline Critical CSS

The HTML parser encounters the `style`-tag and processes the critical CSS right away.
```html
<head>
  <style>
  body {...}
  /* ... rest of the critical CSS */
  </style>
</head>
```

#### Defer uncritical CSS

The uncritical CSS doesn't need to be processed right away. The browser can load it after the onload event so that the user doesn't have to wait.

```html
<link rel="preload" href="/assets/styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/assets/styles.css"></noscript>
```

### 7. JavaScript Asynchronious / Defer loading / lazy-load

JavaScript is HTML parser blocking. The browser has to wait for JavaScript to execute before it can finish parsing the HTML. But you can tell the browser to wait for the JavaScript execution.

#### Load JavaScript asynchronously

With the attribute `async` you tell the browser to load your script asynchronously.

```html
<script src="app.js" async></script>
```
#### Defer JavaScript

The `defer` attribute tells the browser to run the script after the HTML parser finishes parsing the document, but before the event, DOMContentLoaded fires.

```html
<script src="app.js" defer></script>
```

#### Re-order inline scripts

Inline scripts execute right away the browser parses them. Therefore you can place them at the end of your HTML right before the closing body tag.

### 8. Use resource hints to speed up delivery.

[Resource Hints](https://www.w3.org/TR/resource-hints/) help developers to tell the browser what the page later might load. The specification defines four primitives:

- preconnect
- dns-prefetch
- prefetch
- prerender

Additionally, to resource hints, we make use of the [preload](https://www.w3.org/TR/preload/) keyword for the `link`-attribute.

#### preconnect

The following line in your head tells the browser that you want to establish a connection to another domain. The browser will prepare for this connection. Using the preconnect link tag can speed up your load time by 100–500 ms. When do you should use it? Directly speaking: When you know where you what to fetch something but don't know what. Like a hashed style file (`styles.2f2k1kd.css`).
 
 ```html
 <link rel="preconnect" href="https://example.com">
 ```

#### dns-prefetch

You should use preconnect for your most critical connections if you want to tell the browser that you will establish a connection to a non-critical domain you can `dns-prefetch` them. In average, this will save you between 20–120 ms.

 ```html
 <link rel="dns-prefetch" href="http://example.com">
 ```

#### prefetch

With prefetch, you tell the browser to download the entire site that you are referring to in the link tag. You can prefetch pages or assets. Prefetching is a helpful technique to speed up your website, but you should take care of situations where it can decrease your site speed. 

Low-end devices or users on a slow network might have problems because the browser is busily prefetching. You could consider combining prefetching with adaptive loading or use smart prefetching with [quicklink](https://github.com/GoogleChromeLabs/quicklink) and [Guess.js](https://github.com/guess-js)

 ```html
<link rel="prefetch" href="index.html" as="document">
<link rel="prefetch" href="main.js" as="script">
<link rel="prefetch" href="main.css" as="style">
<link rel="prefetch" href="font.woff" as="font">
<link rel="prefetch" href="image.webp" as="image">
 ```

#### prerender

 ```html
<link rel="prerender" href="https://example.com/content/to/prerender">
 ```

With prerendering, the content is loaded and then rendered in the background. When the user navigates to the prerendered content, it is displayed instantly.

#### preload

With preload, the browser gets the hint that the referring asset is important, and it should fetch it sooner. Modern browsers are already pretty good at prioritizing resources so that you should use preload only for critical resources. Consider using preconnect and prefetch instead or try out [instant.page](https://instant.page/).

```html
<link rel="preload" as="script" href="critical.js">
```

### 9. Fasten your Google Fonts

Google Fonts are fantastic. They offer excellent service and are widely used. If you don't want to host your fonts by yourself, Google Fonts is a proper choice. But you should take care of how you implement them. [Harry Roberts](https://csswizardry.com) wrote an excellent in-depth article about [The Fastest Google Fonts](https://csswizardry.com/2020/05/the-fastest-google-fonts/). I strongly recommend you to read it.

If you just want your quick-win use the snippet below for your Google Font integration but the credit goes to Harry.

```html
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
<link rel="preload" as="style" href="https://fonts.googleapis.com/css2?family=...&display=swap"/>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=...&display=swap" media="print" onload="this.media='all'"/>
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=...&display=swap"/></noscript>
```
### 10. Use a service worker to cache your assets

A service worker is a script that your browser runs in the background.  Caching is probably the most used feature and the feature you should use. I think this is not a matter of option. By implementing caching with a service worker, you can make the user interaction with your site faster and make it accessible even if the user is not online.

I wrote a [blog post](https://marcradziwill.com/blog/can-i-use-service-workers-for-my-website/) about how you can implement a service worker. As this article is a 10-minute read, you can also use the code in the [associated repo](https://github.com/marcradziwill/service-worker-tutorial).

## Conclusion <div id="conclusion"></div>

In this post, I presented you 10 Web Performance quick-wins you can apply in under 5 minutes to your website to improve your sites speed. You find the resources in the following [GitHub repo](https://github.com/marcradziwill/web-performance-quick-wins-tutorial).

If you like this article, smile for a moment, share it, follow me, [check out my RSS feed](https://marcradziwill.com/blog/rss.xml) and [subscribe to my newsletter](https://marcradziwill.com/newsletter/).

Cheers Marc

### Further Reading

- [Use text compression](https://web.dev/uses-text-compression/)
- [Optimize images](https://web.dev/uses-optimized-images/)
- [Serve WebP images](https://web.dev/serve-images-webp/)
- [Lazyload images](https://web.dev/use-lazysizes-to-lazyload-images/)
- [HTTP Cache](https://web.dev/http-cache/)
- [Critical CSS](https://web.dev/extract-critical-css/)
- [Third-Party JavaScript](https://web.dev/efficiently-load-third-party-javascript/)
- [Prefetch](https://web.dev/link-prefetch/)
- [Preconnect, dns-prefetch](https://web.dev/preconnect-and-dns-prefetch/)
- [The Fastest Google Fonts by Harry Roberts](https://csswizardry.com/2020/05/the-fastest-google-fonts/)
- [NoModules/Module pattern](https://3perf.com/blog/polyfills/#modulenomodule)
- [Instant.page](https://instant.page/)