Адаптивные изображения: picture, srcset, sizes
Как отдавать каждому устройству ровно ту картинку, которая ему нужна — и не грузить лишние мегабайты.
Адаптивные изображения — это набор атрибутов (
srcset,sizes) и тег<picture>, которые позволяют браузеру самому выбрать оптимальный файл картинки под экран, плотность пикселей и ширину области.
Обычный <img src="photo.jpg"> отдаёт один и тот же файл всем: и Retina-ноутбуку, и дешёвому смартфону на медленном 3G. В результате телефон качает картинку шириной 2000 пикселей, чтобы показать её в колонке шириной 320 — это потерянный трафик и медленная загрузка. Адаптивные изображения решают именно эту проблему, перекладывая выбор файла на браузер, который знает про экран всё.
Зачем это знать на практике
Картинки — обычно самая тяжёлая часть страницы по байтам. На мобильном трафике лишний мегабайт превращается в секунды ожидания и в реальные деньги пользователя. Правильный srcset экономит до 70% веса изображений на маленьких экранах, не теряя резкости на больших. Это напрямую влияет на скорость, на показатели Core Web Vitals и на позиции в поиске.
srcset по плотности пикселей
Самый простой случай — фиксированный размер картинки, но разные экраны по чёткости. Дескриптор x описывает плотность пикселей устройства:
<img src="logo.png"
srcset="logo.png 1x, [email protected] 2x, [email protected] 3x"
width="200" height="60" alt="Логотип">
На обычном мониторе (1x) браузер возьмёт logo.png, на Retina (2x) — вдвое более детальный [email protected]. Атрибут src остаётся запасным для совсем старых браузеров. Этот вариант хорош для логотипов и иконок, чей размер на странице не меняется.
srcset по ширине + sizes
Куда чаще картинка растягивается: на телефоне она во всю ширину, а на десктопе занимает треть экрана. Тогда плотности мало — нужно описать сами файлы по ширине дескриптором w и подсказать браузеру, какого размера будет место под картинку, через sizes:
<img src="hero-800.jpg"
srcset="hero-400.jpg 400w,
hero-800.jpg 800w,
hero-1600.jpg 1600w"
sizes="(max-width: 600px) 100vw, 50vw"
width="800" height="500" alt="Горный пейзаж">
Читается так: «hero-400.jpg имеет ширину 400 пикселей, hero-800.jpg — 800 и так далее». А sizes говорит: «при ширине экрана до 600px картинка займёт всю ширину окна (100vw), иначе — половину (50vw)». Браузер перемножает sizes на плотность своего экрана, получает нужную ширину в пикселях и выбирает ближайший подходящий файл из srcset.
Как браузер считает выбор
Допустим, экран телефона шириной 375px с плотностью 2x. По sizes срабатывает первое условие — 100vw, то есть 375 CSS-пикселей. Умножаем на плотность 2 — нужно ≈750 реальных пикселей. Браузер берёт hero-800.jpg как ближайший сверху. На десктопе 1440px (50vw = 720 CSS-пикселей, плотность 1) он тоже возьмёт 800w. Логика всегда «не меньше требуемого», чтобы не было размытия.
picture и art direction
srcset отдаёт один и тот же кадр в разных размерах. Но иногда на мобильном нужен другой кадр: на десктопе широкая панорама, а на телефоне — вертикальный кроп с лицом крупным планом. Это называется art direction, и для него существует тег <picture>:
<picture>
<source media="(max-width: 600px)" srcset="portrait.jpg">
<source media="(min-width: 601px)" srcset="landscape.jpg">
<img src="landscape.jpg" alt="Команда на встрече">
</picture>
Браузер проверяет <source> сверху вниз и берёт первый, чьё условие media истинно. Обязательный <img> в конце — это и запасной вариант, и носитель атрибута alt: именно к нему привязываются размеры и доступность.
Современные форматы: WebP и AVIF
Тот же <picture> решает вторую задачу — отдать новый формат тем, кто его понимает, и откатиться на JPEG для остальных:
<picture>
<source type="image/avif" srcset="photo.avif">
<source type="image/webp" srcset="photo.webp">
<img src="photo.jpg" alt="Чашка кофе" width="600" height="400">
</picture>
Браузер выберет первый type, который умеет показать. AVIF сжимает заметно сильнее JPEG при том же качестве, WebP — золотая середина с почти всеобщей поддержкой, а photo.jpg остаётся для самых старых клиентов.
| Формат | Сжатие | Поддержка |
| JPEG | базовое | абсолютно везде |
| WebP | на 25–35% меньше | почти все браузеры |
| AVIF | на 50% меньше | современные браузеры |
Ленивая загрузка: loading=lazy
Картинки внизу длинной страницы не нужны, пока пользователь до них не доскроллит. Атрибут loading="lazy" откладывает их загрузку до приближения к области видимости:
<img src="gallery-12.jpg" loading="lazy"
width="400" height="300" alt="Фото из галереи">
Важное исключение: главную картинку первого экрана (LCP-элемент) ленивой делать нельзя — её, наоборот, надо грузить как можно раньше, иначе пострадает скорость отрисовки. Указывайте width и height всегда: зная пропорции, браузер заранее резервирует место и страница не «прыгает» при дозагрузке.
Как это работает под капотом
Алгоритм выбора источника браузер запускает ещё на этапе предзагрузочного сканирования — до построения всего дерева страницы, чтобы начать качать картинку как можно раньше. Для <img srcset sizes> он берёт ширину из sizes, домножает на плотность экрана и ищет в srcset кандидата с подходящим дескриптором w. Для <picture> логика другая: это явный выбор — первый <source>, у которого совпали media и поддерживается type, побеждает безусловно, и браузер уже не «думает» сам. Поэтому picture используют, когда вы хотите контролировать выбор (другой кадр, другой формат), а голый srcset — когда доверяете эвристике браузера.
Частые ошибки
- Путать x и w. Дескриптор
x— для фиксированного размера и разной плотности;w— для растягивающихся картинок и работает только в паре сsizes. - srcset с w без sizes. Без
sizesбраузер считает, что картинка во всю ширину окна, и часто качает слишком большой файл. - Использовать picture там, где хватит srcset. Если кадр один и меняется только размер —
<picture>избыточен, достаточноsrcset. - loading="lazy" на LCP-картинке. Главное изображение первого экрана от этого грузится позже и портит метрику скорости.
- Нет width/height. Браузер не знает пропорций, страница дёргается при дозагрузке (layout shift).
Итоги
srcsetс дескрипторомx— для иконок и логотипов фиксированного размера на экранах разной чёткости.srcsetсw+sizes— для растягивающихся картинок: браузер сам выберет файл по ширине места.<picture>сmedia— art direction: другой кадр под мобильный и десктоп.<picture>сtype— отдать AVIF/WebP поддерживающим, JPEG — остальным.loading="lazy"экономит трафик внизу страницы, но не вешайте его на LCP-картинку; всегда указывайтеwidth/height.