Один и тот же тег <img> может показывать разные файлы картинки в зависимости от экрана - это не магия браузера, а два разных атрибута: srcset отдаёт тот же кадр в разном разрешении (чтобы не грузить огромный файл на маленький экран), а тег <picture> умеет показывать вообще другой кадр - например, квадратную обрезку вместо широкой.
В этом уроке
Сейчас показывается кадр из source (синий) - он побеждает, пока присутствует. Удали всю строку с <source> целиком - картинка сразу переключится на запасной img (оранжевый).
img, srcset и sizes
Атрибут srcset перечисляет несколько файлов одной и той же картинки в разных размерах через запятую, каждый с пометкой ширины в пикселях и буквой w - например, 400w для файла шириной 400 пикселей. Атрибут sizes отдельно сообщает браузеру, какую реальную ширину картинка займёт в вёрстке при разной ширине экрана - без него браузер не может правильно посчитать, какой файл из списка выбрать.
<img src="/images/koshka-800.jpg" srcset="/images/koshka-400.jpg 400w, /images/koshka-800.jpg 800w, /images/koshka-1200.jpg 1200w" sizes="(max-width: 600px) 100vw, 600px" alt="Рыжая кошка спит на подоконнике"> - три файла на выбор и честно указано, сколько места картинка займёт на странице.
<img src="/images/koshka-800.jpg" srcset="/images/koshka-400.jpg 400px, /images/koshka-800.jpg 800px" alt="Рыжая кошка спит на подоконнике"> - дескриптор должен заканчиваться на w, а не на px: с такой записью браузер не распознаёт кандидатов и просто покажет обычный src.
picture и source
Тег <picture> нужен, когда на разных экранах должен показываться не просто более лёгкий файл того же кадра, а вообще другой кадр - например, квадратная обрезка портрета для мобильного экрана вместо широкого группового фото для десктопа. Внутри <picture> можно перечислить несколько <source> с условием media, а в конце обязательно нужен обычный <img> - именно он покажется, если ни одно условие не подошло, а также в старых браузерах, которые вообще не понимают picture.
<picture><source media="(max-width: 600px)" srcset="/images/koshka-kvadrat.jpg"><img src="/images/koshka-shirokaya.jpg" alt="Рыжая кошка на подоконнике"></picture> - есть запасной img, картинка покажется в любом случае.
<picture><source media="(max-width: 600px)" srcset="/images/koshka-kvadrat.jpg"></picture> - без img внутри: если условие не подошло (или браузер не знает picture), не покажется вообще ничего.
Частые ошибки новичков
| Ошибка | Что происходит | Как исправить |
|---|---|---|
| Писать дескриптор ширины как "400px" вместо "400w" в srcset | Браузер не распознаёт кандидатов, srcset не срабатывает, показывается обычный src | Всегда заканчивать дескриптор буквой w: "400w", "800w" |
| Использовать w-дескрипторы в srcset без атрибута sizes | Браузер считает, что картинка займёт всю ширину экрана, и может выбрать файл крупнее, чем нужно на самом деле | Указывать sizes с реальной шириной, которую картинка займёт в вёрстке |
| Оставлять source внутри picture без запасного img | Если ни одно условие source не подошло (или браузер не поддерживает picture) - не покажется вообще ничего | Всегда добавлять img последним элементом внутри picture |
| Использовать srcset там, где на самом деле нужен другой кадр, а не просто разрешение полегче | На широком экране просто увеличится тот же кадр вместо показа другой, более уместной композиции | Для разных кадров (art direction) нужен picture с source, а не srcset у обычного img |
Шпаргалка
| Термин | Значение |
|---|---|
| srcset | Список файлов того же кадра в разных размерах с дескриптором ширины (например, 400w) |
| sizes | Реальная ширина, которую картинка займёт в вёрстке - нужен для работы w-дескрипторов |
| picture | Контейнер с несколькими вариантами картинки и обязательным запасным img внутри |
| source | Вариант картинки внутри picture с условием media (или форматом type) |
Коротко: отвечаем на вопросы
Что будет, если у img со srcset (через w-дескрипторы) не указать sizes?
По умолчанию браузер посчитает, что картинка займёт всю ширину экрана - sizes="100vw". Если на самом деле картинка в вёрстке занимает меньше места, браузер может выбрать файл крупнее, чем реально нужно, и скачать лишние килобайты зря.
Обязательно ли добавлять img внутри picture?
Да, обязательно, и именно последним элементом. Он служит запасным вариантом сразу для двух случаев: когда ни одно условие media у source не подошло, и когда браузер вообще не поддерживает picture - тогда он просто покажет img и проигнорирует незнакомые ему source.
Чем srcset у обычного img отличается от picture - когда что использовать?
srcset у img - это переключение разрешения: браузер сам выбирает файл того же кадра, подходящий по размеру экрана. picture нужен для другой задачи - художественного кадрирования, когда на разных экранах должен показываться не просто более лёгкий файл, а другая композиция кадра (например, квадратная обрезка вместо широкой).