Серверна оптимізація зображень: WebP, AVIF, стиснення

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 2062 послуг
Серверна оптимізація зображень: WebP, AVIF, стиснення
Середній
~2-3 дні
Часті запитання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1362
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1253
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    958
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1190
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    931
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Розробка веб-сайту для компанії ФІКСПЕР
    949

Уявіть: ви завантажуєте на сайт зображення 10 МБ, а відвідувач з мобільним інтернетом іде, не дочекавшись завантаження. Важкі картинки — головна причина поганого LCP (Largest Contentful Paint) і високого показника відмов. Ми стикалися з цим десятки разів: клієнт скаржиться на повільний сайт, а винні неоптимізовані JPEG з метаданими EXIF по 500 КБ кожен. Серверна оптимізація зображень вирішує цю проблему докорінно: автоматичне стиснення з втратами і без, конвертація в сучасні формати WebP та AVIF, динамічна зміна розміру — все це знижує обсяг переданих даних на 40–70% без втрати якості. Оптимізація зображень безпосередньо впливає на Core Web Vitals, особливо LCP та CLS, що підвищує позиції в пошуковій видачі. У нашій практиці грамотний пайплайн зменшив LCP з 4,2 с до 1,1 с для інтернет-магазину з тисячами товарів. Згідно з Wikipedia, WebP — формат зображень, що забезпечує чудове стиснення.

Як серверна оптимізація зображень прискорює завантаження сайту?

При завантаженні зображення на сервер запускається пайплайн: бібліотека Sharp або Intervention Image змінює розмір до заданих максимальних ширин (400, 800, 1200, 1920 пікселів), конвертує в WebP та AVIF, видаляє EXIF-дані. Потім згенеровані файли кешуються на CDN з довгим терміном життя. Браузер отримує маленький файл у підтримуваному форматі — сторінка завантажується миттєво. На відміну від клієнтської оптимізації (стиснення через JavaScript), серверний підхід не навантажує пристрій користувача і однаково ефективний для будь-якого трафіку.

Чому варто обрати WebP та AVIF?

Формат Тип стиснення Середнє зменшення Підтримка браузерів
JPEG З втратами 1x (базовий) 100%
WebP З втратами/без втрат 25-35% менше JPEG 96%
AVIF З втратами/без втрат 50% менше JPEG 85%

AVIF краще за стисненням, WebP — за сумісністю. Оптимальна стратегія — генерувати обидва формати і передавати через <picture> з srcset.

Наш стек для серверної оптимізації

У Node.js проектах використовуємо бібліотеку Sharp — вона забезпечує високу пропускну здатність і мінімальне споживання пам'яті. Для PHP-застосунків застосовуємо Intervention Image у зв'язці з Imagick. Приклади коду реалізовано нижче.

Node.js: Sharp pipeline

import sharp from 'sharp';

interface OptimizeOptions {
  maxWidth?: number;
  quality?: number;
  format?: 'webp' | 'avif' | 'jpeg';
}

async function optimizeImage(inputBuffer: Buffer, options: OptimizeOptions = {}): Promise<Buffer> {
  const { maxWidth = 1920, quality = 80, format = 'webp' } = options;

  return sharp(inputBuffer)
    .resize(maxWidth, undefined, {
      withoutEnlargement: true,
      fit: 'inside',
    })
    .toFormat(format, {
      quality,
      effort: 4,  // баланс скорость/размер
    })
    .withMetadata({ orientation: undefined })  // убрать EXIF rotation
    .toBuffer();
}

// Middleware для lazy оптимизации
app.get('/images/:key', async (req, res) => {
  const { key } = req.params;
  const { w, q = '80', f = 'webp' } = req.query;

  // Проверить кэш
  const cacheKey = `${key}:${w}:${q}:${f}`;
  const cached = await s3.getObject({ Key: `optimized/${cacheKey}.${f}` }).catch(() => null);

  if (cached) {
    return res.type(`image/${f}`).send(await streamToBuffer(cached.Body));
  }

  // Получить оригинал
  const original = await s3.getObject({ Key: `originals/${key}` });
  const buffer = await streamToBuffer(original.Body);

  // Оптимизировать
  const optimized = await optimizeImage(buffer, {
    maxWidth: w ? parseInt(w as string) : 1920,
    quality: parseInt(q as string),
    format: f as 'webp' | 'avif' | 'jpeg',
  });

  // Сохранить в кэш
  await s3.putObject({
    Key: `optimized/${cacheKey}.${f}`,
    Body: optimized,
    ContentType: `image/${f}`,
    CacheControl: 'public, max-age=31536000',
  });

  res.type(`image/${f}`).send(optimized);
});

PHP: оптимізація при завантаженні

use Intervention\Image\Facades\Image;

class ImageOptimizationService
{
    const FORMATS = ['webp', 'avif'];
    const SIZES = [400, 800, 1200, 1920];

    public function process(UploadedFile $file): array
    {
        $image = Image::make($file->getPathname());

        // Убрать EXIF и повернуть по ориентации
        $image->orientate()->stripExif();

        $paths = [];

        foreach (self::SIZES as $width) {
            if ($image->width() < $width) continue;

            $resized = clone $image;
            $resized->resize($width, null, fn($c) => $c->aspectRatio()->upsize(false));

            foreach (self::FORMATS as $format) {
                $quality = $format === 'avif' ? 60 : 82;
                $key = "images/{$width}w/{$this->generateKey()}.{$format}";

                Storage::disk('s3')->put(
                    $key,
                    $resized->encode($format, $quality)->__toString(),
                    ['CacheControl' => 'public, max-age=31536000']
                );

                $paths[$format][$width] = $key;
            }
        }

        return $paths;
    }
}

HTML: responsive images з srcset

// Blade хелпер для отображения оптимизированных изображений
function responsive_img(array $paths, string $alt, string $sizes = '100vw'): string
{
    $avifSrcset = collect($paths['avif'] ?? [])->map(fn($path, $width) =>
        Storage::disk('s3')->url($path) . " {$width}w"
    )->join(', ');

    $webpSrcset = collect($paths['webp'] ?? [])->map(fn($path, $width) =>
        Storage::disk('s3')->url($path) . " {$width}w"
    )->join(', ');

    $fallback = Storage::disk('s3')->url(end($paths['webp']));

    return <<<HTML
<picture>
  <source type="image/avif" srcset="{$avifSrcset}" sizes="{$sizes}">
  <source type="image/webp" srcset="{$webpSrcset}" sizes="{$sizes}">
  <img src="{$fallback}" alt="{$alt}" loading="lazy" decoding="async">
</picture>
HTML;
}

Зверніть увагу на атрибут alt: він повинен містити ключове слово, наприклад «оптимізоване зображення товару», що також допомагає SEO.

Nginx: конвертація WebP на льоту

# Отдавать WebP если браузер поддерживает
map $http_accept $webp_suffix {
    "~*webp"  ".webp";
    default   "";
}

server {
    location ~* \.(jpg|jpeg|png)$ {
        add_header Vary Accept;
        try_files $uri$webp_suffix $uri =404;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

Процес роботи

  1. Аналіз — аудит поточних зображень: середній розмір, формати, метадані. Визначаємо точки зростання.
  2. Проектування пайплайну — обираємо стратегію: on‑the‑fly (Nginx + ImageMagick) або pre‑process при завантаженні. Проектуємо систему кешування.
  3. Реалізація — пишемо код оптимізації, налаштовуємо обробник завантаження, додаємо srcset для responsive images.
  4. Тестування — перевіряємо візуальну якість, метрики Core Web Vitals, швидкість віддачі. Використовуємо Lighthouse та PageSpeed Insights.
  5. Деплой — розгортаємо на сервері, підключаємо CDN (Cloudflare, AWS CloudFront), налаштовуємо моніторинг.

Що входить в роботу

  • Інтеграція пайплайну оптимізації (Sharp/Intervention) у ваш бекенд.
  • Генерація кількох розмірів (400, 800, 1200, 1920 px) для responsive images.
  • Конвертація в WebP та AVIF з оптимальною якістю.
  • Стріппінг метаданих (EXIF) для додаткової економії.
  • Налаштування кешування через CDN з long‑lived Cache-Control.
  • Документація з використання хелперів (Blade, Twig, JSX).
  • Підтримка після впровадження — 14 днів моніторингу.

Чек-лист для оцінки поточного пайплайну:

  • використання сучасних форматів (WebP/AVIF);
  • застосування стриппінгу метаданих;
  • генерація різних розмірів для responsive;
  • налаштування кешування на CDN;
  • використання lazy loading та async decoding.

Терміни реалізації

Компонент Орієнтовний термін
Базова інтеграція Sharp при завантаженні 2–3 дні
On‑the‑fly конвертація через Nginx +1–2 дні
Повний пайплайн з responsive srcset та CDN 4–5 днів

Вартість розраховується індивідуально під ваш проект — залежить від стеку, кількості точок завантаження та вимог до кешування. При середньому обсязі трафіку економія може бути суттєвою. Зв'яжіться з нами для оцінки, і ми запропонуємо оптимальне рішення.

Замовте реалізацію серверної оптимізації зображень під ключ — ваш сайт стане значно швидшим. За 7+ років роботи ми оптимізували зображення для більш ніж 50 проектів — від невеликих блогів до високонавантажених інтернет-магазинів. Гарантуємо зниження розміру картинок мінімум на 40% при збереженні якості.

Чому Core Web Vitals критичні для технічного SEO

PageSpeed показує 34/100 на мобільних. У Search Console — червоні метрики по всіх сторінках категорій. Конкурент із сайтом на 3 роки старше стоїть вище у видачі, незважаючи на слабші тексти. Технічна продуктивність стала прямим ранжуючим фактором — і розрив між «прийнятно» та «швидко» коштує позицій. Ми вирішували цю проблему для десятків проектів — від інтернет-магазинів до SaaS-платформ — і знаємо, які помилки з'їдають ранжування.

Як досягти хороших показників Core Web Vitals?

Core Web Vitals: що реально впливає на позиції

Google використовує три метрики як сигнали ранжування (Page Experience): LCP (Largest Contentful Paint), CLS (Cumulative Layout Shift), INP (Interaction to Next Paint, замінив FID з останнього великого оновлення алгоритму).

LCP: чому 8 секунд — це не проблема зображення

LCP вимірює час відмальовки найбільшого видимого елемента сторінки. Найчастіше — hero image або H1. Пороги: добре < 2.5s, погано > 4s.

Типовий діагноз на реальному проекті: інтернет-магазин одягу, LCP 7.8s на мобільних. Елемент — hero image категорії, 4.2MB JPEG без srcset, завантажується через CSS background-image (не <img>). Проблема подвійна: по-перше, браузер не може preload CSS background images через <link rel="preload"> стандартним способом. По-друге, 4.2MB на мобільному з'єднанні — це фізично повільно.

Рішення по кроках:

  1. Переносимо hero з CSS background в <img> з fetchpriority="high" та loading="eager"
  2. Конвертуємо в WebP, додаємо srcset: 800w для мобільних, 1400w для десктопа
  3. <link rel="preload" as="image" href="hero-800.webp" media="(max-width: 768px)"> в <head>
  4. Прибираємо всі render-blocking скрипти вище hero через defer

Підсумок: LCP 7.8s → 1.9s. Без зміни хостингу, без CDN.

Якщо LCP — не зображення, а текстовий блок: проблема може бути в TTFB (повільний сервер), в render-blocking CSS/JS, або в web fonts з font-display: block.

CLS: зсуви, які дратують користувача і Google

CLS вимірює сумарний зсув елементів в процесі завантаження. Пороги: добре < 0.1, погано > 0.25. CLS 0.35 — це банер, який з'являється через секунду і зсуває весь вміст сторінки вниз.

Джерела CLS:

  • Зображення без заданих розмірів. <img src="photo.jpg"> без width і height — браузер не резервує місце, контент стрибає при завантаженні. Фікс: явні width/height або aspect-ratio в CSS.
  • Рекламні блоки та віджети. Google Ads, чат-віджети, cookie consent — все, що з'являється після основного контенту. Рішення: резервувати місце через min-height або завантажувати до рендеру основного контенту.
  • Web fonts. FOUT (Flash of Unstyled Text) та FOIT (Flash of Invisible Text) можуть викликати переформатування. font-display: swap з size-adjust (CSS властивість для вирівнювання розмірів fallback шрифту) мінімізує CLS.
  • Динамічний контент. Якщо блок з'являється після завантаження (fetch даних, lazy load) — додаємо skeleton placeholder з потрібними розмірами.
Типовий сценарій CLS до CLS після Основний фікс
Банер знижок без min-height 0.42 0.02 min-height: 300px
Картинки в статтях без атрибутів 0.18 0.01 width/height + aspect-ratio
Віджет чату, що завантажується через 3с 0.35 0.05 position: fixed із зарезервованим відступом

INP: чому інтерфейс «зависає» на 500ms

INP вимірює затримку відповіді на будь-яку взаємодію користувача: клік, тап, введення. Пороги: добре < 200ms, погано > 500ms. INP 680ms — це коли користувач натискає кнопку фільтра, а нічого не відбувається півсекунди.

Головна причина високого INP — заблокований main thread. JavaScript-бандл 2.1MB парситься і виконується синхронно. Поки виконується, користувацькі події не обробляються.

Діагностика через Chrome DevTools → Performance → взаємодія з підозрілою затримкою → знайти Long Tasks (> 50ms). Типові винуватці:

  • Безперервна обробка великого списку без requestIdleCallback або requestAnimationFrame
  • Важкі event listeners без debounce/throttle
  • Синхронний setState в React, який тригерить повний ре-рендер складного дерева компонентів
  • Third-party scripts: livechat, аналітика, віджети — вони виконуються в тому ж main thread

Рішення: code splitting через динамічний import(), перенесення важких обчислень в Web Workers, React.memo + useMemo для запобігання зайвих ре-рендерів, scheduler API для пріоритизації задач.

Schema.org: розмітка, яку читають роботи

Структуровані дані через JSON-LD — не прямий ранжуючий фактор, але дають rich snippets у видачі (зірки рейтингів, ціни, дата публікації), що збільшує CTR на 20–30%.

Типи розмітки за сценаріями:

  • E-commerce: Product з offers (ціна, наявність, валюта), aggregateRating (рейтинг з відгуків), brand. BreadcrumbList для навігації. ItemList для сторінок категорій.
  • Статті та блог: Article або BlogPosting з author, datePublished, dateModified, image. Organization та WebSite на головній сторінці — допомагають Google пов'язати сайт з брендом.
  • Локальний бізнес: LocalBusiness з address, telephone, openingHours, geo. Критично для локального SEO.
  • FAQ: FAQPage з mainEntity — питання та відповіді можуть з'являтися прямо у видачі як розкривний блок.

Валідація: Google Rich Results Test та Schema Markup Validator. Часта помилка — вказати price без priceCurrency, або ratingValue без reviewCount. Google ігнорує неповну розмітку.

Як проводити технічний SEO-аудит

Сканованість. robots.txt блокує потрібні сторінки (або навпаки, не блокує службові). Canonical URLs налаштовані неправильно — дублюються сторінки з UTM-мітками. Sitemap містить сторінки з noindex. Все це Screaming Frog або Sitebulb покажуть за годину сканування.

Core Web Vitals в масштабі. Google Search Console → Core Web Vitals → дивимося не окремі сторінки, а групи URL (шаблон сторінки продукту, шаблон категорії, блог). Проблема зазвичай системна — одна помилка в шаблоні псує сотні сторінок.

JavaScript SEO. Google рендерить JavaScript, але з затримкою (іноді дні для повного рендеру). Для критичного контенту — SSR або SSG обов'язкові. Перевіряємо через Search Console → Inspect URL → View Crawled Page: що бачить Googlebot.

Internal linking. Орфанні сторінки (немає вхідних внутрішніх посилань) втрачають PageRank. Бите посилання (404) — сигнал якості.

Типові помилки при впровадженні Schema.org
  • Вказано price без priceCurrency — розмітка ігнорується.
  • ratingValue без reviewCount — у видачі не показується.
  • Кілька Product на одній сторінці без @type: ItemList — Google бере тільки перший.
  • JSON-LD в GTM — Google не завжди бачить динамічну розмітку, краще серверний рендеринг.
Етап роботи Що входить Термін
Аудит Сканування, аналіз Core Web Vitals, аудит Schema, звіт з пріоритетами 1–2 тижні
Оптимізація одного шаблону LCP, CLS, INP, впровадження SSR/SSG, налаштування preload 2–4 тижні
Повна технічна оптимізація Всі шаблони, code splitting, Web Workers, моніторинг в CI 4–10 тижнів
Впровадження Schema.org JSON-LD генерація, валідація, тестування rich snippets 1–3 тижні

Що входить в роботу

  • Документація: звіт зі знайденими проблемами, roadmap за пріоритетами, таймінги для кожного етапу.
  • Доступи: налаштування моніторингу (SpeedCurve, Sentry Search Console), передача dashboard.
  • Навчання: розбір типових помилок для вашої команди (1–2 дзвінки).
  • Підтримка: супровід протягом місяця після деплою — перевірка метрик, фікс регресій.

Зв'яжіться з нами — ми оцінимо ваш проект за 2 дні і покажемо, скільки позицій можна повернути за рахунок технічного SEO. Досвід роботи з проектами рівня сотень тисяч відвідувань на місяць — гарантуємо вимірний результат в Core Web Vitals до/після. Замовте аудит у цій формі — отримайте персональний чек-лист з 15 пунктів.