Back to list
yonatangross

image-optimization

by yonatangross

The Complete AI Development Toolkit for Claude Code — 159 skills, 34 agents, 20 commands, 144 hooks. Production-ready patterns for FastAPI, React 19, LangGraph, security, and testing.

29🍴 4📅 Jan 23, 2026

SKILL.md


name: image-optimization description: Image optimization with Next.js 15 Image, AVIF/WebP formats, blur placeholders, responsive sizes, and CDN loaders. Use when improving image performance, responsive sizing, or Next.js image pipelines. tags: [images, next-image, avif, webp, responsive, lazy-loading, blur-placeholder, lcp] context: fork agent: frontend-ui-developer version: 1.0.0 allowed-tools: [Read, Write, Grep, Glob] author: OrchestKit user-invocable: false

Image Optimization

Production image optimization patterns for modern web applications.

Overview

  • Optimizing Largest Contentful Paint (LCP)
  • Reducing page weight and bandwidth
  • Implementing responsive images
  • Adding blur placeholders for perceived performance
  • Converting to modern formats (AVIF, WebP)

Core Patterns

1. Next.js Image Component

import Image from 'next/image';

// Static import (recommended for static assets)
import heroImage from '@/public/hero.jpg';

function Hero() {
  return (
    <Image
      src={heroImage}
      alt="Hero banner"
      priority // Preload for LCP
      placeholder="blur" // Automatic blur placeholder
      quality={85}
      sizes="100vw"
    />
  );
}

// Remote images
<Image
  src="https://cdn.example.com/photo.jpg"
  alt="Remote photo"
  width={800}
  height={600}
  sizes="(max-width: 768px) 100vw, 800px"
/>

2. Responsive Images with Sizes

// Full-width hero
<Image
  src="/hero.jpg"
  alt="Hero"
  fill
  sizes="100vw"
  style={{ objectFit: 'cover' }}
/>

// Sidebar image (smaller on large screens)
<Image
  src="/sidebar.jpg"
  alt="Sidebar"
  width={400}
  height={300}
  sizes="(max-width: 768px) 100vw, 33vw"
/>

// Grid of cards
<Image
  src={`/products/${id}.jpg`}
  alt={product.name}
  width={300}
  height={300}
  sizes="(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 25vw"
/>

3. Blur Placeholders

// Static imports get automatic blur
import photo from '@/public/photo.jpg';
<Image src={photo} alt="Photo" placeholder="blur" />

// Remote images need blurDataURL
<Image
  src="https://cdn.example.com/photo.jpg"
  alt="Photo"
  width={800}
  height={600}
  placeholder="blur"
  blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..."
/>

// Generate blurDataURL at build time
import { getPlaiceholder } from 'plaiceholder';

export async function getStaticProps() {
  const { base64 } = await getPlaiceholder('/public/photo.jpg');
  return { props: { blurDataURL: base64 } };
}

4. Format Selection (AVIF/WebP)

// next.config.js - Enable AVIF
module.exports = {
  images: {
    formats: ['image/avif', 'image/webp'],
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
  },
};

// HTML picture element for non-Next.js
<picture>
  <source srcSet="/hero.avif" type="image/avif" />
  <source srcSet="/hero.webp" type="image/webp" />
  <img src="/hero.jpg" alt="Hero" width="1200" height="600" />
</picture>

5. Lazy Loading Patterns

// Default: lazy loading (below the fold)
<Image src="/photo.jpg" alt="Photo" width={400} height={300} />

// Above the fold: eager loading
<Image
  src="/hero.jpg"
  alt="Hero"
  width={1200}
  height={600}
  priority // Preloads, no lazy loading
/>

// Native lazy loading (non-Next.js)
<img
  src="/photo.jpg"
  alt="Photo"
  loading="lazy"
  decoding="async"
  width="400"
  height="300"
/>

6. Image CDN Configuration

// next.config.js - External image domains
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'cdn.example.com',
        pathname: '/images/**',
      },
      {
        protocol: 'https',
        hostname: '*.cloudinary.com',
      },
    ],
  },
};

// Cloudinary loader
const cloudinaryLoader = ({ src, width, quality }) => {
  return `https://res.cloudinary.com/demo/image/upload/w_${width},q_${quality || 75}/${src}`;
};

<Image
  loader={cloudinaryLoader}
  src="sample.jpg"
  alt="Cloudinary image"
  width={500}
  height={300}
/>

7. Art Direction (Different Images per Breakpoint)

'use client';
import Image from 'next/image';
import { useMediaQuery } from '@/hooks/useMediaQuery';

function ResponsiveHero() {
  const isMobile = useMediaQuery('(max-width: 768px)');

  return (
    <Image
      src={isMobile ? '/hero-mobile.jpg' : '/hero-desktop.jpg'}
      alt="Hero"
      fill
      priority
      sizes="100vw"
    />
  );
}

// Or use CSS to swap
<div className="relative h-[400px]">
  <Image
    src="/hero-desktop.jpg"
    alt="Hero"
    fill
    className="hidden md:block object-cover"
  />
  <Image
    src="/hero-mobile.jpg"
    alt="Hero"
    fill
    className="md:hidden object-cover"
  />
</div>

8. SVG and Icon Optimization

// Inline SVG for small icons (avoid network requests)
import { IconCheck } from '@/components/icons';
<IconCheck className="w-4 h-4" />

// SVG sprites for many icons
<svg className="hidden">
  <symbol id="icon-check" viewBox="0 0 24 24">...</symbol>
  <symbol id="icon-close" viewBox="0 0 24 24">...</symbol>
</svg>

<svg className="w-4 h-4">
  <use href="#icon-check" />
</svg>

// Large decorative SVGs: use Image component
<Image src="/illustration.svg" alt="" width={400} height={300} />

Performance Metrics Impact

OptimizationLCP ImpactCLS ImpactBandwidth
AVIF format-20-30% loadNone-50% size
Responsive sizes-30-50% loadNone-40% size
Blur placeholderPerceived fasterPrevents shift+1kb
Priority loading-500ms+NoneNone
Lazy loadingNone (below fold)NoneDeferred

Anti-Patterns to Avoid

Anti-PatternProblemSolution
No width/heightCLS from layout shiftAlways set dimensions
Eager load allSlow initial loadUse lazy loading
No priority on LCPSlow LCPAdd priority prop
PNG for photosLarge file sizeUse AVIF/WebP
Single image sizeWasted bandwidthUse responsive sizes

Build-Time Optimization

# Sharp for Next.js (auto-installed)
npm install sharp

# Squoosh CLI for batch optimization
npx @squoosh/cli --webp '{"quality":80}' --avif '{"quality":65}' ./images/*

Quick Reference

// ✅ LCP Hero Image (static import for blur)
import heroImage from '@/public/hero.jpg';
<Image
  src={heroImage}
  alt="Hero"
  priority
  placeholder="blur"
  sizes="100vw"
  fill
/>

// ✅ Remote image with explicit dimensions
<Image
  src="https://cdn.example.com/photo.jpg"
  alt="Photo"
  width={800}
  height={600}
  sizes="(max-width: 768px) 100vw, 800px"
/>

// ✅ Responsive product card
<Image
  src={product.image}
  alt={product.name}
  fill
  sizes="(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 25vw"
/>

// ✅ next.config.js for AVIF/WebP
images: {
  formats: ['image/avif', 'image/webp'],
  remotePatterns: [{ hostname: 'cdn.example.com' }],
}

// ❌ NEVER: Missing dimensions (causes CLS)
<Image src="/photo.jpg" alt="Photo" /> // Missing width/height!

// ❌ NEVER: Priority on non-LCP images
<Image src="/footer-logo.png" priority /> // Wastes bandwidth

// ❌ NEVER: Using PNG for photos
<Image src="/photo.png" /> // Use AVIF/WebP instead

Key Decisions

DecisionOption AOption BRecommendation
Image formatJPEG/PNGAVIF/WebPAVIF (30-50% smaller), WebP fallback
Next.js ImageStatic importRemote URLStatic import for automatic blur placeholder
Lazy loadingAlways lazyPriority for LCPPriority for LCP, lazy for rest
Quality setting10075-8575-85 - imperceptible difference, much smaller
PlaceholderNoneBlurBlur - better perceived performance
DimensionsFill modeExplicit w/hFill with aspect-ratio container for flexibility

Anti-Patterns (FORBIDDEN)

// ❌ FORBIDDEN: Missing width/height (causes CLS)
<Image src="/photo.jpg" alt="Photo" />
// ✅ CORRECT: Always set dimensions
<Image src="/photo.jpg" alt="Photo" width={800} height={600} />

// ❌ FORBIDDEN: Using fill without container sizing
<div>
  <Image src="/photo.jpg" alt="Photo" fill /> {/* No container size! */}
</div>
// ✅ CORRECT: Fill needs sized container
<div className="relative h-[400px]">
  <Image src="/photo.jpg" alt="Photo" fill />
</div>

// ❌ FORBIDDEN: priority on all images
{images.map(img => (
  <Image src={img.url} alt={img.alt} priority /> // All priority!
))}
// ✅ CORRECT: Only LCP image gets priority
<Image src={heroImage} priority /> {/* LCP only */}
{belowFoldImages.map(img => (
  <Image src={img.url} alt={img.alt} /> /* Default lazy */
))}

// ❌ FORBIDDEN: No sizes prop on responsive images
<Image src="/photo.jpg" fill /> // No sizes = 100vw assumed always
// ✅ CORRECT: Always specify sizes
<Image src="/photo.jpg" fill sizes="(max-width: 768px) 100vw, 50vw" />

// ❌ FORBIDDEN: Using remote images without allowlist
<Image src="https://untrusted.com/image.jpg" /> // Not in remotePatterns!
// ✅ CORRECT: Configure remotePatterns in next.config.js

// ❌ FORBIDDEN: PNG for photographs
<img src="/photo.png" /> // PNG is for transparency, not photos
// ✅ CORRECT: Use AVIF/WebP for photos
<Image src="/photo.jpg" /> // Next.js converts to AVIF/WebP

// ❌ FORBIDDEN: Quality 100
<Image quality={100} /> // Huge file, no visual benefit
// ✅ CORRECT: Quality 75-85
<Image quality={85} />

// ❌ FORBIDDEN: Loading LCP content via client-side fetch
useEffect(() => {
  fetchHeroImage().then(setHero); // LCP waits for JS + fetch!
}, []);
// ✅ CORRECT: Server-render LCP images
export default async function Page() {
  const hero = await getHero();
  return <Image src={hero.image} priority />;
}

// ❌ FORBIDDEN: Empty alt on non-decorative images
<Image src="/product.jpg" alt="" /> // Inaccessible!
// ✅ CORRECT: Meaningful alt text
<Image src="/product.jpg" alt="Red sneakers, side view" />
  • core-web-vitals - LCP optimization, performance monitoring
  • accessibility-specialist - Image alt text, WCAG compliance
  • react-server-components-framework - Server-rendering for LCP images
  • frontend-ui-developer - Modern frontend patterns

Capability Details

next-image

Keywords: next/image, Image component, fill, priority, sizes, quality Solves: Automatic optimization, format conversion, responsive images

avif-webp

Keywords: AVIF, WebP, format, compression, modern-formats Solves: Reducing image file size by 30-50% with same quality

blur-placeholder

Keywords: blur, placeholder, blurDataURL, plaiceholder, perceived-performance Solves: Better perceived performance, visual stability during load

responsive-sizes

Keywords: sizes, srcset, responsive, breakpoint, viewport Solves: Serving appropriately-sized images for each device

image-cdn

Keywords: CDN, Cloudinary, imgix, Cloudflare, loader, remote Solves: Global distribution, on-demand transformation, caching

lazy-loading

Keywords: lazy, loading, priority, eager, preload, LCP Solves: Reducing initial page load by deferring off-screen images

References

  • references/cdn-setup.md - Image CDN configuration
  • scripts/image-component.tsx - Reusable image wrapper
  • checklists/image-checklist.md - Optimization checklist
  • examples/image-examples.md - Real-world image patterns

Score

Total Score

75/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

+10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon