Уявіть: ви завантажуєте на сайт зображення 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";
}
}
Процес роботи
- Аналіз — аудит поточних зображень: середній розмір, формати, метадані. Визначаємо точки зростання.
- Проектування пайплайну — обираємо стратегію: on‑the‑fly (Nginx + ImageMagick) або pre‑process при завантаженні. Проектуємо систему кешування.
- Реалізація — пишемо код оптимізації, налаштовуємо обробник завантаження, додаємо srcset для responsive images.
- Тестування — перевіряємо візуальну якість, метрики Core Web Vitals, швидкість віддачі. Використовуємо Lighthouse та PageSpeed Insights.
- Деплой — розгортаємо на сервері, підключаємо 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% при збереженні якості.







