A Simple Approach to LCP Image Optimization with TwicPics Components
Tags: webperf, images, nuxt, nextjs
Published: 2024-02-05 09:24:40


---
title: A Simple Approach to LCP Image Optimization with TwicPics Components
published: true
description:  Discover an easy solution to streamline Largest Contentful Paint (LCP) image optimization in your web projects.
tags: webperf, images, Nuxt, Next
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aygat1eloog2v1f44uge.jpg
series: TwicPics Components
## Use a ratio of 100:42 for best results.
## published_at: 2024-02-02 09:58 +0000
---

In a [previous article](https://www.twicpics.com/blog/optimizing-the-image-element-lcp), we delved into the common challenges of optimizing the **Largest Contentful Paint** (LCP) for images.
We explored best practices and showed how [TwicPics](https://www.twicpics.com/) streamlines the implementation of [resolution switching](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images#resolution_switching_same_size_different_resolutions) through its user-friendly [API](https://www.twicpics.com/docs/guides/writing-api-requests) and a **single master image**.

While the **use of a single source file** for all resolutions is already a **significant improvement**, it's evident that the code implementation is still **complex** and **lengthy**. Furthermore, the proposed solution does not optimize the [Cumulative Layout Shift](https://web.dev/articles/optimize-cls) and does not allow for [Art direction](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images#art_direction).

In this short tutorial, we will see how [TwicPics Components](https://www.twicpics.com/docs/essentials/components) (more precisely, the `TwicPicture` component) makes it easy to address all these issues.

The solution makes the most sense in a framework that handles [SSR](https://www.sanity.io/glossary/server-side-rendering), and we have chosen to create an example of its usage with [Nuxt 3](https://nuxt.com/). Of course, you are free to use the [framework of your choice](https://www.twicpics.com/docs/essentials/components#supported-frameworks).
 
> This tutorial requires using Node.js <strong>v18.0.0+</strong> and TwicPics Components <strong>0.27.0+</strong>.

## Scaffold your new Nuxt 3 Project

> You can skip this part if you want to integrate TwicPics Components into an existing Nuxt 3 project.

### Setup

```shell
# creates a new starter project
npx nuxi@latest init <project-name>
```

Pick your preferred dependency manager (we chose `yarn`) and wait for your new project to be created.

You can now `cd` into your new project directory.

### Start Nuxt

```shell
# starts and open your Nuxt app in development mode
yarn dev --open
```

If all goes well, `Nuxt` should now be serving your project on http://localhost:3000/ and you should see something like this:

| ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ja838gloeyfi9q67vzq8.jpeg) |
|:--:| 
| <center>Nuxt is running</center> |

If you get stuck at any point, you can refer to the [Nuxt getting started page](https://nuxt.com/docs/getting-started/installation).

## Install and configure TwicPics Components

Now that `Nuxt` is up and running, it is time to add and configure the [Nuxt version of the TwicPics components](https://www.twicpics.com/docs/components/nuxt-3).

> In the following, we will use our test domain:<code>https://demo.twic.pics</code>
> If you don't have a TwicPics domain yet, you can easily <a href="https://account.twicpics.com/signup" target="_blank">create your own for free</a>.

### Install TwicPics Components

Add the `@twicpics/components` package to your project:

```shell
# using yarn
yarn add @twicpics/components
```

### Setting-up TwicPics Components

Since **TwicPics components** for `Nuxt3` are packaged as a [module](https://nuxt.com/modules?category=Images), integration and configuration take place in the `nuxt.config.ts` file:

```ts
// nuxt.config.ts
export default defineNuxtConfig({
  // integration
  modules: [`@twicpics/components/nuxt3`],
  // configuration
  twicpics: {
    domain: `https://demo.twic.pics`, // set your own domain here
  },
});
```

And that's it. You are now ready to to use **TwicPics components** in your project.

## TwicPicture enters the scene

As a remember, optimizing the display of _LCP_ images, or more generally, _critical_ images in a web project, we need to fill the `srcset` attribute of an `img` tag with a list of differently-sized versions of the **same image**. This is called [resolution switching](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images#resolution_switching_same_size_different_resolutions).

For example, at the end of the [article]((https://www.twicpics.com/blog/optimizing-the-image-element-lcp)) discussing _LCP_ image optimization, we had this code:

```html
<img
  src="https://<your-domain>/<path-to-your-image>?twic=v1/resize=280"
  srcset="
    https://<your-domain>/<path-to-your-image>?twic=v1/resize=280   280w,
    https://<your-domain>/<path-to-your-image>?twic=v1/resize=480   480w,
    https://<your-domain>/<path-to-your-image>?twic=v1/resize=560   560w,
    https://<your-domain>/<path-to-your-image>?twic=v1/resize=840   840w,
    https://<your-domain>/<path-to-your-image>?twic=v1/resize=960   960w,
    https://<your-domain>/<path-to-your-image>?twic=v1/resize=1440 1440w
  "
/>
```

To do the same thing with `TwicPicture`, all we have to do is:

```html
<TwicPicture src="path-to-your-image"/>
```

Let's verify this in our project by making the following changes to the `app.vue` file using [puppy-dressed-as-a-reindeer.jpeg](https://assets.twicpics.com/examples/puppy-dressed-as-a-reindeer.jpeg) (`jpeg` - 6777 x 3812 px - 15.28 MB) as master file image :

```html
// app.vue
<template>
  <TwicPicture
    src="puppy-dressed-as-a-reindeer.jpeg"
  />
</template>
```

Here is the generated code:

```html
<img 
  alt="" 
  width="1536" 
  height="1536"
  loading="lazy" 
  srcset="
    https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=3072x3072 3072w,
    https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=2560x2560 2560w,
    https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=2048x2048 2048w,
    https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=1536x1536 1536w,
    https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=1280x1280 1280w,
    https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=1024x1024 1024w,
    https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=768x768 768w,
    https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=640x640 640w,
    https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=320x320 320w
  " 
  src="https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=1536x1536"
>
```

And this is what we should get on a `DPR2` device when changing the viewport width from a small to a wide screen:


| ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ll5ipkwabsrlbtpl5d5c.gif) |
|:--:| 
| <center>A Resolution Switching in action.</center> |

We obtain various **squared** variants, ideally compressed (`webp`), whose resolution is tailored to both the _viewport_ and the _pixel density_ of the device: **resolution switching is fully functional**.

To achieve the same result while showcasing an image in `16:9` format, we just need to modify `app.vue` as follows:

```html
// app.vue
<template>
  <TwicPicture
    src="puppy-dressed-as-a-reindeer.jpeg"
    ratio="16/9"
  />
</template>
```

And this is what we get, this time on a `DPR1` screen:

| ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nk1vorhyu6ssrn5vdozf.gif) |
|:--:| 
| <center>Resolution Switching for a 16:9 variant.</center> |

`TwicPicture` allows the display of images not only with **various resolutions** but also with **different aspect ratios**, all **from a single master file**.

You can find the complete list of `TwicPicture` properties [here](https://www.twicpics.com/docs/components/nuxt-3#twicpicture). Later on we'll explore how to leverage additional [powerful transformations](https://www.twicpics.com/docs/reference/transformations).

## Design Control

Now that we know `TwicPicture` allows for managing **aspect ratio** along with **resolution switching**, it's time to explore how to implement [Art Direction](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images#art_direction).

Let's reopen our `app.vue` file and modify it by configuring the `ratio` property following the **mobile-first principle**:

```html
// app.vue
<!--
  This will display a:
  - 3/4 variant for small screen with width < 666px (a custom breakpoint is used here)
  - squared variant for screen with width ∈ [ 666px, 768px [
  - 4/3 variant for screen with width ∈ [ 768px, 1024px [
  - 21/9 variant for screen with width >= 1280px
-->
<template>
  <TwicPicture
    src="components/puppy-dressed-as-a-reindeer.jpeg"
    ratio="
      3/4
      @666 1
      @md 4/3
      @xl 21/9
    "
  />
</template>
```

>  <a href="https://www.twicpics.com/docs/components/nuxt-3#default-breakpoints" target="_blank">Default breakpoint values</a> are customizable during components  <a href="https://www.twicpics.com/docs/components/nuxt-3#setup-options" target="_blank">configuration</a>.

Here is the result on a `DPR1` screen:

| ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2yb7y6v0tjbxl6p9dkup.gif) |
|:--:| 
| <center>One single master file with art direction.</center> |

The result is moderately satisfying: we achieve the **desired aspect ratios based on the screen size**, but the image is poorly framed in its 21/9 variant. Let's fix the framing by adjusting the focus for that specific breakpoint:

```html
// app.vue
<!--
  This will apply:
  - default focus transformation for screen with width < 1280px
  - focus="top" transformation for screen with width >= 1280px
-->
<template>
  <TwicPicture
    src="components/puppy-dressed-as-a-reindeer.jpeg"
    focus="@xl top"
    ratio="
      3/4
      @666 1
      @md 4/3
      @xl 21/9
    "
  />
</template>
```

This is the generated code:

```html
<picture>
  <source
    height="549"
    width="1280"
    media="(min-width: 1280px)" 
    srcset="
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/focus=top/cover=3072x1317 3072w,https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/focus=top/cover=2560x1097 2560w,https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/focus=top/cover=1536x658 1536w,https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/focus=top/cover=1280x549 1280w
    " 
  >
  <source
    height="576"
    width="768"
    media="(min-width: 768px)"
    srcset="
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=2048x1536 2048w,
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=1536x1152 1536w,
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=1024x768 1024w,
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=768x576 768w
    "
  >
  <source
    height="666"
    width="666"
    media="(min-width: 666px)"
    srcset="
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=1332x1332 1332w,
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=666x666 666w
    "
    >
  <img
    alt=""
    height="888"
    width="666" 
    loading="lazy"
    srcset="
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=1280x1707 1280w,
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=640x853 640w,
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=320x427 320w
      " 
  >
</picture>
```

And this is the result with a fixed focus on wide screen:

| ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xlk0nbgq9cvg0tm7iq0j.gif) |
|:--:| 
| <center>A true art direction.</center> |


Other properties of `TwicPicture` are configurable based on breakpoints, allowing simple and great flexibility in the implementation of _Art Direction_.

Feel free to explore the [documentation](https://www.twicpics.com/docs/components/nuxt-3#art-direction) for a deeper understanding of `TwicPicture` and its _design control_ feature.

## Handling Best Practices

### Don't forget the sizes

So far, we have displayed an image that occupies the entire width of the viewport.

Let's modify our example to restrict the width of our image to a maximum of `1200px`. Like this:

```html
// app.vue
<template>
  <div class="container">
    <TwicPicture
      src="components/puppy-dressed-as-a-reindeer.jpeg"
      focus="@xl top"
      ratio="
        3/4
        @666 1
        @md 4/3
        @xl 21/9
      "
      sizes="
        (max-width: 1200px) 100vw,
        1200px
      "
    />
  </div>
</template>

<style>
.container {
  margin: auto;
  max-width: 1200px;
}
</style>
```

You've noticed that we used the `sizes` property to inform the browser about the **effective size of the image** to be displayed for a given viewport width.

Without this property, the browser would have loaded the image corresponding to **100% of the viewport**, potentially increasing loading times and **impacting the LCP score**.

It's an **easy trap to fall into**, so it's crucial not to forget to assign a value to the `sizes` property.

Here is the result, with and without `sizes`: 

| ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c9hgevvrd2tia4w5kfhj.gif) |
|:--:| 
| <center>Don't forget the sizes.</center> |

Here, forgetting to assign a value to the `sizes` property **multiplies the weight of the image by 4**!

### Improve LCP Resource Load Delay Subpart

In our [previous article](https://www.twicpics.com/blog/optimizing-the-image-element-lcp#improve-lcp-resource-load-delay-subpart) about Image Element _LCP_ optimization, we discussed the issue of **lazy-loading** and **priority hints**.

With `TwicPicture`, applying best practices to **improve LCP score** is as simple as adding the `eager` property to our component call: this will effectively **disable lazy loading** for this image and set `fetchpriority` attribute to `high`.

```html
// app.vue
<template>
  <div class="container">
    <TwicPicture
      src="components/puppy-dressed-as-a-reindeer.jpeg"
      eager
      focus="@xl top"
      ratio="
        3/4
        @666 1
        @md 4/3
        @xl 21/9
      "
      sizes="
        (max-width: 1200px) 100vw,
        1200px
      "
    />
  </div>
</template>

<style>
.container {
  margin: auto;
  max-width: 1200px;
}
</style>
```

This time the generated code becomes 

```html
<picture>
  <source
    height="549"
    width="1280"
    media="(min-width: 1280px)" 
    srcset="
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/focus=top/cover=3072x1317 3072w,https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/focus=top/cover=2560x1097 2560w,https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/focus=top/cover=1536x658 1536w,https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/focus=top/cover=1280x549 1280w
    " 
  >
  <source
    height="576"
    width="768"
    media="(min-width: 768px)"
    srcset="
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=2048x1536 2048w,
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=1536x1152 1536w,
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=1024x768 1024w,
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=768x576 768w
    "
  >
  <source
    height="666"
    width="666"
    media="(min-width: 666px)"
    srcset="
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=1332x1332 1332w,
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=666x666 666w
    "
    >
  <img
    alt=""
    fetchpriority="high"
    height="888"
    width="666" 
    loading="eager"
    sizes="
      (max-width: 1200px) 100vw,
      1200px
    "
    srcset="
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=1280x1707 1280w,
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=640x853 640w,
      https://demo.twic.pics/puppy-dressed-as-a-reindeer.jpeg?twic=v1/cover=320x427 320w
      " 
  >
</picture>
```

## The Trial by Fire

It's time to check the _LCP_ score of a web page using `TwicPicture`.

To do this, we've created a [small demonstration site](https://twicpics-lcp-images-with-twicpicture.netlify.app/) where, in addition to `TwicPicture` which handles the _LCP_ image, we use [TwicImg](https://www.twicpics.com/docs/essentials/components#display-a-content-image) to display content images.

Here is the result of the performance audit with [Chrome's Lighthouse](https://chromewebstore.google.com/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk?hl=fr):

| ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r525nmlr1355fpkmmae1.png) |
|:--:| 
| <center>The Trial by Fire</center> |

Our page achieves a performance score of **100%** with a _LCP_ metric equal to **0.5 s**.

Significantly the _CLS_ metric is **zero** as [TwicPics Components](https://www.twicpics.com/docs/essentials/components), by default, seamlessly optimize _Cumulative Layout Shift_.

## To go further

Suppose the background color of the main image isn't exactly right. Or the protagonist's orientation isn't correct.
Should we take another photo?

Fortunately, the answer is no. TwicPics [API](https://www.twicpics.com/docs/guides/writing-api-requests) and its [transformations](https://www.twicpics.com/docs/reference/transformations) lets you make these adjustments on the fly.

For example, to change the background color to blue `#145480` and orient the puppy's head on the other side, simply use the following transformation `background=remove+145480/flip=x`.

To apply it to our main image, simply modify the app.vue file by adding the `preTransform` property as follows:

```html
// app.vue
  ...
    <TwicPicture
      src="components/puppy-dressed-as-a-reindeer.jpeg"
      eager
      focus="@xl top"
      preTransform="background=remove+145480/flip=x"
      ratio="
        3/4
        @666 1
        @md 4/3
        @xl 21/9
      "
      sizes="
        (max-width: 1200px) 100vw,
        1200px
      "
    />
  ...
```

And that's it:

| ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cukoh84hdzxnbcduou9c.gif) |
|:--:| 
| <center>Using stunning transformations on the fly.</center> |

If you want to learn more about the versatile options offered by `TwicPicture`, feel free to explore its [properties](https://www.twicpics.com/docs/components/nuxt-3#twicpicture).

## Conclusion

The proper display of a _critical image_ on a web page involves the use of `picture`, `source`, and `img` tags. The associated code is often verbose, time-consuming to develop, and may lead to poor results.

[TwicPics Components](https://www.twicpics.com/docs/essentials/components), particularly the `TwicPicture` component, stands out as a robust and efficient solution for optimizing the _Largest Contentful Paint_ (LCP) in web projects, with best practices out of the box, including _Cumulative Layout Shift_ (CLS) optimization.

Whether the objective is to achieve **optimal performance** or manage **design control**, `TwicPicture` comprehensively and flexibly addresses these challenges, offering a streamlined approach to handling _critical images_. Additionally, it provides the capability to leverage the power of [TwicPics](https://www.twicpics.com/): **perfectly compressed images**, rich and scalable [transformations](https://www.twicpics.com/docs/reference/transformations), and the benefits of its **worldwide CDN proximity**.

In this tutorial, we used [Nuxt3](https://nuxt.com/) to assess the ease of use and effectiveness of `TwicPicture`. The [source code](https://github.com/TwicPics/components-demo-twic-picture/) for the test project is at your disposal, allowing you to conduct your own experiments freely. Feel free to replicate the same in the [framework of your choice](https://www.twicpics.com/docs/essentials/components#supported-frameworks).

[TwicPics Components](https://www.npmjs.com/package/@twicpics/components) are both free and open-source. You can test them for yourself **without any cost**. The only requirement is to have a **TwicPics account**, which you can easily create for free by [signing up here](https://account.twicpics.com/signup).