DEV Community

Jen C.
Jen C.

Posted on • Edited on

1 1

Optimize Core Web Vitals - FCP and LCP: Images

Pre-study

Resources

Serve images in next-gen formats

Next.js Image Component Documentation

Image Optimization

Next.js Image Optimization Guide
Fix your website's Largest Contentful Paint by optimizing image loading

HTMLImageElement Properties

Decoding Property

FetchPriority Property

Loading Property

Solution 1: Migrate <img> to Next.js Image Component

Conversion

Replace <img> elements with the Next.js Image component.

<img ... />
Enter fullscreen mode Exit fullscreen mode

To:

import Image from 'next/image';

<Image ... />
Enter fullscreen mode Exit fullscreen mode

Local Images

Importing from Public Folder

Remote Images

Note: Provide either width and height or use fill.

Known Width and Height (or Aspect Ratio)

Set width and height based on the intrinsic aspect ratio of the image.

Unknown Width and Height

Extracting Width and Height from Image URL

For example, imgUrl:

'http://image-transfer.my.com/myProject/image/upload/ar_1:1,w_700,c_pad,b_auto:predominant/v12345/artist.png';
Enter fullscreen mode Exit fullscreen mode

Helper Function:

const parseNum = (value, fallback) => {
  const num = Number(value);
  return isNaN(num) ? fallback : num;
};

export const getDimensionsFromImgUrl = (imgUrl) => {
  const defaultSize = 1;
  const arDelimiter = 'ar_';
  const widthDelimiter = 'w_';

  const parts = imgUrl.split(',');
  const arPart = parts.find((part) => part.includes(arDelimiter));
  const widthPart = parts.find((part) => part.includes(widthDelimiter));

  if (!arPart || !widthPart)
    return { width: defaultSize, height: defaultSize };

  const width = parseNum(widthPart.split(widthDelimiter)[1], defaultSize);
  const [w, h] = (arPart.split(arDelimiter)[1]?.split(':') || [defaultSize, defaultSize]).map((size) => parseNum(size, defaultSize));
  const height = Math.round(width * (h / w));

  return { width, height };
};
Enter fullscreen mode Exit fullscreen mode

Usage:

const { width, height } = getDimensionsFromImgUrl(imgUrl);
Enter fullscreen mode Exit fullscreen mode
When Width and Height Cannot Be Extracted

Create a custom image component using the onload event to set dimensions.

Note: This may cause layout shift.

const DynamicImage = ({ logo, alt, imgUrl }) => {
  const [dimensions, setDimensions] = useState({ width: 100, height: 100 }); // Fallback values

  useEffect(() => {
    const img = new window.Image();
    img.src = imgUrl;
    img.onload = () => {
      setDimensions({ width: img.width, height: img.height });
    };
  }, [imgUrl]);

  return (
    <NextImage
      className={classNames(
        { 'page-header__img': !logo.isCP },
        { 'page-header-cp__img': logo.isCP },
        { 'page-header__img--sm': logo.sm }
      )}
      src={imgUrl}
      alt={alt}
      width={dimensions.width}
      height={dimensions.height}
    />
  );
};
Enter fullscreen mode Exit fullscreen mode

Errors and Solutions

Error: 'sharp' is required in standalone mode for image optimization

Solution:

Solution 2: Use Next.js Image for Known Dimensions Only

Since Next.js Image requires width and height (or fill), it is recommended to use it only when dimensions are known.

Other Images: Add Attributes to <img>

For unknown dimensions, continue using the <img> tag with relevant attributes based on requirements.

For example, for LCP (Largest Contentful Paint) images:

<img
  decoding='async'
  fetchPriority='high'
  loading='eager'
  src={resizeImg(imgUrl, 'lg', { ar })}
  alt={imgAlt}
/>
Enter fullscreen mode Exit fullscreen mode

For non-LCP images:

<img
  decoding='async'
  fetchPriority='low'
  loading='lazy'
  src={resizeImg(imgUrl, 'lg', { ar })}
  alt={imgAlt}
/>
Enter fullscreen mode Exit fullscreen mode

Heroku

Built for developers, by developers.

Whether you're building a simple prototype or a business-critical product, Heroku's fully-managed platform gives you the simplest path to delivering apps quickly — using the tools and languages you already love!

Learn More

Top comments (0)

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →