Гайд по использованию тега picture

Тег <picture> — это мощный инструмент для адаптивной подачи изображений в HTML. Он позволяет браузеру выбирать оптимальное изображение в зависимости от характеристик устройства пользователя: размер экрана, плотность пиксельной сетки (Retina), тема оформления и другие медиавыражения. Это критично для оптимизации производительности, особенно для мобильных пользователей.

Основная концепция

Без тега <picture> мы загружаем одно изображение для всех устройств. Если это полноразмерная фотография 2000×1500px, то мобильный пользователь будет загружать этот тяжёлый файл, хотя его экран всего 375px в ширину. Пустая трата трафика и времени.

С помощью <picture> браузер анализирует доступные варианты и загружает только нужный. Мобильник получит оптимизированную версию, а десктоп — полноценное изображение высокого качества.

Синтаксис и структура

HTML
<picture>
  <source srcset="small.jpg" media="(max-width: 600px)">
  <source srcset="medium.jpg" media="(max-width: 1200px)">
  <source srcset="large.jpg" media="(min-width: 1201px)">
  <img src="large.jpg" alt="Описание изображения">
</picture>

Важные правила:

  • <picture> — контейнер, который сам изображение не выводит
  • <source> — помогает выбрать правильный URL (может быть несколько)
  • <img> — обязателен, именно он отображает картинку (это элемент по умолчанию)
  • Браузер читает <source> по порядку и выбирает первый подходящий
  • Если медиавыражение не сработает и нет подходящих <source> — используется <img src>

Три основных сценария использования

1. Адаптивность по размеру экрана

Это самый частый случай. Для маленьких экранов мы даём маленькую картинку, для больших — большую.

HTML
<picture>
  <source srcset="photo-320.jpg" media="(max-width: 480px)">
  <source srcset="photo-768.jpg" media="(max-width: 1024px)">
  <source srcset="photo-1920.jpg">
  <img src="photo-1920.jpg" alt="Панорама горного пейзажа">
</picture>

Как это работает:

  • Если окно браузера ≤ 480px → загружается photo-320.jpg
  • Если окно 481px–1024px → загружается photo-768.jpg
  • Если окно > 1024px → загружается photo-1920.jpg

Экономия трафика:

  • Мобильный пользователь (320px): вместо 500KB полноразмерного файла загружает 45KB
  • Планшет (768px): вместо 500KB загружает 120KB
  • Десктоп (1920px): загружает 500KB для лучшего качества

2. Поддержка высокоплотных дисплеев (Retina)

На MacBook Pro и современных смартфонах плотность пиксельной сетки выше (2x, 3x). Картинка размером 750px на Retina дисплее будет пиксельной. Нужна версия с двойным разрешением.

HTML
<picture>
  <source srcset="icon-1x.png 1x, icon-2x.png 2x, icon-3x.png 3x">
  <img src="icon-1x.png" alt="Иконка профиля">
</picture>

Или комбинированный подход:

HTML
<picture>
  <source 
    srcset="photo-750.jpg 1x, photo-1500.jpg 2x"
    media="(max-width: 800px)">
  <source 
    srcset="photo-1280.jpg 1x, photo-2560.jpg 2x"
    media="(min-width: 801px)">
  <img src="photo-1280.jpg" alt="Основное изображение">
</picture>

Что здесь происходит:

  • На обычном мобильном экране (1x): загружается photo-750.jpg
  • На iPhone с Retina (2x): загружается photo-1500.jpg (есть смысл в лучшем качестве)
  • На десктопе (1x): загружается photo-1280.jpg
  • На MacBook Retina (2x): загружается photo-2560.jpg

3. Адаптация под тёмную тему

Современные браузеры могут определять предпочтения пользователя. Если у него включена тёмная тема — покажем тёмный вариант изображения.

HTML
<picture>
  <source srcset="logo-dark.png" media="(prefers-color-scheme: dark)">
  <img src="logo-light.png" alt="Логотип компании">
</picture>

Продвинутые техники

Использование различных форматов изображений

Не все браузеры поддерживают WebP или AVIF. Тогда будем использовать <source> с атрибутом type для подачи разных форматов:

HTML
<picture>
  <source srcset="image.avif" type="image/avif">
  <source srcset="image.webp" type="image/webp">
  <source srcset="image.jpg" type="image/jpeg">
  <img src="image.jpg" alt="Картинка">
</picture>

Приоритет браузера:

  1. Проверяет поддержку image/avif → если поддерживает, загружает AVIF
  2. Если нет → проверяет WebP
  3. Если нет → берёт JPEG

Это даёт нам огромное преимущество в производительности. AVIF может быть в 2–3 раза меньше, чем JPEG, при том же визуальном качестве.

Комбинированный подход (размер + формат + плотность)

HTML
<picture>
  <!-- Для мобильных с WebP -->
  <source 
    srcset="hero-mobile.webp 1x, hero-mobile-2x.webp 2x"
    media="(max-width: 768px)"
    type="image/webp">
  <!-- Для мобильных, если нет WebP -->
  <source 
    srcset="hero-mobile.jpg 1x, hero-mobile-2x.jpg 2x"
    media="(max-width: 768px)">
  
  <!-- Для десктопа с WebP -->
  <source 
    srcset="hero-desktop.webp 1x, hero-desktop-2x.webp 2x"
    type="image/webp">
  <!-- Для десктопа, если нет WebP -->
  <img 
    srcset="hero-desktop.jpg 1x, hero-desktop-2x.jpg 2x"
    src="hero-desktop.jpg" 
    alt="Главный баннер сайта">
</picture>

Это выглядит сложновато, но браузер справляется без проблем. Мы даём ему несколько вариантов — он выбирает оптимальный.

Стилизация <picture>

Важный момент: сам тег <picture> — это не блочный контейнер, как <div>. Это семантический контейнер. Стили нужно применять к вложенному <img>:

CSS
/* Неправильно */
picture {
  width: 100%;
  max-width: 800px;
}

/* Правильно */
picture img {
  width: 100%;
  max-width: 800px;
  height: auto;
  display: block;
}

Если нужно задать класс для большего контроля:

HTML
<picture class="hero-image">
  <source srcset="hero-mobile.webp" media="(max-width: 768px)">
  <img src="hero-desktop.jpg" alt="Заголовок">
</picture>
CSS
.hero-image img {
  width: 100%;
  height: auto;
  object-fit: cover;
  object-position: center;
}

Частые ошибки

❌ Ошибка 1: Забытый <img>

HTML
<!-- Браузер ничего не покажет! -->
<picture>
  <source srcset="image.jpg" media="(max-width: 768px)">
</picture>

Тег <img> нужен всегда. Он — якорь, который гарантирует, что картинка появится.

❌ Ошибка 2: Стили на <picture> вместо <img>

CSS
/* Не работает так, как ожидаем */
picture {
  width: 100%;
  border-radius: 8px;
}
CSS
/* Правильно */
picture img {
  width: 100%;
  border-radius: 8px;
}

❌ Ошибка 3: Неправильный порядок <source>

HTML
<!-- Неправильно: от общего к частному -->
<picture>
  <source srcset="large.jpg">
  <source srcset="small.jpg" media="(max-width: 600px)">
  <img src="large.jpg" alt="">
</picture>

Браузер выберет первый подходящий. Если large.jpg без медиавыражения — он всегда подходит. Правильный порядок:

HTML
<!-- Правильно: от частного к общему -->
<picture>
  <source srcset="small.jpg" media="(max-width: 600px)">
  <source srcset="medium.jpg" media="(max-width: 1200px)">
  <source srcset="large.jpg">
  <img src="large.jpg" alt="">
</picture>

Практические советы веб-разработчику

  1. Автоматизация генерации версий изображений — используй инструменты типа ImageMagick, Sharp (Node.js) или онлайн-сервисы для создания нескольких версий. Вручную это делать утомительно.
  2. Правильный alt-текст — добавляй его в <img>, он критичен для SEO и доступности. На <source> alt не добавляется.
  3. Проверка поддержки браузером<picture> поддерживается во всех современных браузерах (IE 11 и старше — не поддерживают, но это уже древность).
  4. Инструменты для оптимизации:
    • TinyPNG/TinyJPG — сжатие
    • Squoosh (Google) — конвертация в WebP/AVIF
    • ImageOptim (Mac) — пакетное сжатие
  5. На продакшене — рассмотри использование Image CDN (Cloudinary, Imgix), которые автоматически подают правильные размеры и форматы в зависимости от User-Agent браузера.

Реальный пример: адаптивное изображение для статьи

HTML
<picture class="article-hero">
  <!-- Мобильные устройства, WebP -->
  <source 
    srcset="article-hero-480w.webp 1x, article-hero-960w.webp 2x"
    media="(max-width: 640px)"
    type="image/webp">
  <!-- Мобильные устройства, fallback JPEG -->
  <source 
    srcset="article-hero-480w.jpg 1x, article-hero-960w.jpg 2x"
    media="(max-width: 640px)">
  
  <!-- Планшеты, WebP -->
  <source 
    srcset="article-hero-800w.webp 1x, article-hero-1600w.webp 2x"
    media="(max-width: 1024px)"
    type="image/webp">
  <!-- Планшеты, fallback JPEG -->
  <source 
    srcset="article-hero-800w.jpg 1x, article-hero-1600w.jpg 2x"
    media="(max-width: 1024px)">
  
  <!-- Десктоп, WebP -->
  <source 
    srcset="article-hero-1200w.webp 1x, article-hero-2400w.webp 2x"
    type="image/webp">
  <!-- Десктоп, fallback JPEG -->
  <img 
    srcset="article-hero-1200w.jpg 1x, article-hero-2400w.jpg 2x"
    src="article-hero-1200w.jpg"
    alt="Стена с граффити — иллюстрация к статье о уличном искусстве">
</picture>
CSS
.article-hero img {
  width: 100%;
  height: auto;
  display: block;
  max-width: 1200px;
}

Этот пример охватывает все случаи: разные размеры экрана, плотность дисплея и форматы изображений. Браузер выберет оптимальное.