Назад к блогу
Frontend

Оптимизация изображений: WebP, AVIF и lazy loading

Полное руководство по оптимизации изображений: форматы WebP и AVIF, lazy loading, responsive images, CDN и blur placeholder.

5 января 2026 г.
9 мин чтения
128 просмотров
MOLOTILO

MOLOTILO DIGITAL

Оптимизация изображений: WebP, AVIF и lazy loading

Почему оптимизация изображений важна

Изображения составляют 50-70% веса страницы. Правильная оптимизация критически влияет на скорость загрузки, Core Web Vitals и пользовательский опыт.

Современные форматы

ФорматСжатиеПоддержкаПрименение
JPEGХорошее100%Фото
PNGБез потерь100%Графика, прозрачность
WebPОтличное97%Универсальный
AVIFЛучшее85%Фото, где поддерживается
<!-- Fallback для старых браузеров -->
<picture>
  <source srcset="/image.avif" type="image/avif" />
  <source srcset="/image.webp" type="image/webp" />
  <img src="/image.jpg" alt="Description" />
</picture>

Next.js Image Component

Next.js автоматически оптимизирует изображения:

import Image from 'next/image';

// Базовое использование
<Image
  src="/hero.jpg"
  alt="Hero image"
  width={1200}
  height={600}
  priority  // Для LCP изображений
/>

// Responsive изображение
<Image
  src="/product.jpg"
  alt="Product"
  fill
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
  className="object-cover"
/>

// С blur placeholder
import heroImage from '@/public/hero.jpg';

<Image
  src={heroImage}
  alt="Hero"
  placeholder="blur"  // Автоматический blur для статических импортов
/>

// Динамический blur placeholder
<Image
  src={dynamicUrl}
  alt="Dynamic"
  placeholder="blur"
  blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..."
/>

Конфигурация Next.js

// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'images.unsplash.com',
      },
      {
        protocol: 'https',
        hostname: 'cdn.example.com',
      }
    ],
    formats: ['image/avif', 'image/webp'],
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048],
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
    minimumCacheTTL: 60 * 60 * 24 * 30, // 30 дней
  }
};

Lazy Loading

// Native lazy loading
<img src="/image.jpg" alt="..." loading="lazy" />

// Next.js Image — lazy по умолчанию
<Image src="/image.jpg" alt="..." width={800} height={600} />

// Отключение lazy для важных изображений
<Image
  src="/hero.jpg"
  alt="Hero"
  width={1200}
  height={600}
  priority  // Загружается сразу
  loading="eager"
/>

// Intersection Observer для кастомной логики
function LazyImage({ src, alt }) {
  const [isVisible, setIsVisible] = useState(false);
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setIsVisible(true);
          observer.disconnect();
        }
      },
      { rootMargin: '100px' }
    );

    if (ref.current) observer.observe(ref.current);
    return () => observer.disconnect();
  }, []);

  return (
    <div ref={ref}>
      {isVisible ? (
        <img src={src} alt={alt} />
      ) : (
        <div className="skeleton" />
      )}
    </div>
  );
}

Responsive Images

<!-- srcset для разных размеров экрана -->
<img
  src="/image-800.jpg"
  srcset="
    /image-400.jpg 400w,
    /image-800.jpg 800w,
    /image-1200.jpg 1200w
  "
  sizes="(max-width: 600px) 100vw, 50vw"
  alt="Responsive image"
/>

<!-- Art direction с picture -->
<picture>
  <source
    media="(max-width: 767px)"
    srcset="/hero-mobile.webp"
  />
  <source
    media="(max-width: 1023px)"
    srcset="/hero-tablet.webp"
  />
  <img src="/hero-desktop.webp" alt="Hero" />
</picture>

CDN и кэширование

// Cloudinary URL API
function getOptimizedUrl(publicId: string, options: ImageOptions) {
  const { width, height, quality = 'auto', format = 'auto' } = options;
  
  return `https://res.cloudinary.com/demo/image/upload/` +
    `w_${width},h_${height},c_fill,q_${quality},f_${format}/` +
    publicId;
}

// Использование
<img src={getOptimizedUrl('products/shoe', { width: 400, height: 400 })} />

// Imgix
const imgixUrl = `/placeholders/image-placeholder.svg?w=800&auto=format,compress`;

Генерация blur placeholder

// Генерация base64 blur на сервере
import sharp from 'sharp';

async function generateBlurPlaceholder(imagePath: string): Promise<string> {
  const buffer = await sharp(imagePath)
    .resize(10, 10, { fit: 'inside' })
    .blur()
    .toBuffer();
  
  return `data:image/jpeg;base64,${buffer.toString('base64')}`;
}

// Использование с Prisma
const product = await prisma.product.findUnique({
  where: { id },
  select: {
    image: true,
    blurDataURL: true
  }
});

<Image
  src={product.image}
  alt="Product"
  placeholder="blur"
  blurDataURL={product.blurDataURL}
/>

Чек-лист оптимизации

  1. ✅ Используйте WebP/AVIF с fallback
  2. ✅ Указывайте width и height (избегаем CLS)
  3. ✅ Lazy loading для изображений ниже fold
  4. ✅ priority для LCP изображений
  5. ✅ Responsive sizes для разных экранов
  6. ✅ Blur placeholder для лучшего UX
  7. ✅ CDN для быстрой доставки

Заключение

Оптимизация изображений — один из самых эффективных способов улучшить производительность. Next.js Image делает большую часть работы автоматически. Используйте современные форматы, lazy loading и CDN для максимальной скорости.

Каждый сэкономленный килобайт — это быстрее загрузка и лучший UX. Оптимизируйте изображения в первую очередь.

ИзображенияОптимизацияWebPPerformanceNext.js

Понравилась статья?

Подпишитесь на наш блог, чтобы не пропустить новые материалы