[РУКОВОДСТВО] 10 мин чтения

[РУКОВОДСТВО] Разбираем data URI: data:image/png;base64,... простыми словами

Практическое руководство по схеме data: URI — что на самом деле означает каждая часть data:image/png;base64,iVBORw0KGgo..., когда встраивание оправдано и когда оно играет против вас.

April 2026 | fundamentals

// ЧТО ТАКОЕ data: URI НА САМОМ ДЕЛЕ

data: URI — это URI-схема, как https: или file:, которая встраивает сам ресурс прямо в строку URI вместо того, чтобы указывать на удалённое расположение. Определена в RFC 2397 и позволяет обращаться с небольшим бинарным или текстовым фрагментом данных так, будто это URL.

Самая распространённая форма, которую вы встретите на практике, — для изображений: data:image/png;base64,iVBORw0KGgoAAAANSUhEUg.... Браузер видит этот URL, считывает MIME-тип, декодирует Base64-полезную нагрузку обратно в байты и отрисовывает изображение — без единого HTTP-запроса.

// СИНТАКСИС ПО ЧАСТЯМ

Полный синтаксис: data:[<mediatype>][;base64],<data>. Три необязательные части и один обязательный разделитель (запятая). Разберём реальный пример:

Возьмём data:image/png;base64,iVBORw0KGgoAAAANSUhEUg... и прочтём слева направо:
data: — схема. Сообщает парсеру: «ресурс находится в самом URL, никаких запросов делать не нужно».
image/png — MIME-тип. Сообщает рендереру, как интерпретировать полезную нагрузку. По умолчанию text/plain;charset=US-ASCII, если опущен.
;base64 — флаг кодирования. Указывает, что полезная нагрузка закодирована в Base64 (RFC 4648). Без него полезная нагрузка интерпретируется как URL-кодированный текст.
, — обязательный разделитель между метаданными и полезной нагрузкой.
iVBORw0KGgo... — собственно Base64-кодированные байты изображения.

// Anatomy diagram
// data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...
// │    │         │      │
// │    │         │      └── Base64 payload (the actual image bytes)
// │    │         └────────── encoding flag (always 'base64' for binary)
// │    └──────────────────── MIME type (optional, defaults to text/plain)
// └───────────────────────── scheme literal (always 'data:')

// ЗАЧЕМ СУЩЕСТВУЮТ data: URI

Три причины, по которым к data URI прибегают вместо обычных URL изображений:

1. Убрать HTTP-запрос. Каждый <img src="..."> на странице стоит сетевого round-trip. Для крошечной иконки или спрайта этот round-trip может занять больше времени, чем сама передача байт. Встраивание изображения в виде data URI объединяет его с HTML/CSS, полностью убирая запрос. Это сильно играло роль в эпоху HTTP/1.1; с мультиплексированием HTTP/2 это менее критично, но для критических иконок выше «сгиба» по-прежнему помогает.

2. Сделать ресурс самодостаточным. HTML-письмо должно отображаться в клиентах, которые по умолчанию блокируют удалённые изображения (Gmail, Outlook). Статический отчёт, отправленный клиенту по почте, должен показывать логотип компании даже офлайн. Букмарклету нужна иконка, переживающая копирование-вставку. Фрагменту документации нужен скриншот, путешествующий вместе с markdown. Во всех этих случаях изображение должно жить внутри документа — и data URI как раз даёт такую возможность.

3. Программная генерация. Код во время выполнения генерирует изображение — QR-код, диаграмму, поле для подписи — и его нужно отобразить, не загружая сначала на сервер и не получая обратно URL. canvas.toDataURL('image/png') отдаёт data URI напрямую; присвоить его img.src — простейший возможный сценарий.

// ВСЕ MIME-ТИПЫ, КОТОРЫЕ ВАМ РЕАЛЬНО ВСТРЕТЯТСЯ

Слот MIME-типа принимает любой медиа-тип, но на практике для изображений вы будете видеть несколько:

image/png — самый распространённый. Без потерь, поддерживает прозрачность. Base64 начинается с iVBORw0KGgo.
image/jpeg — фотографии и скриншоты. С потерями. Base64 начинается с /9j/.
image/gif — устаревший формат и анимированные изображения. Base64 начинается с R0lGOD.
image/webp — современный, файлы меньше. Base64 начинается с UklGR.
image/svg+xml — векторная графика. SVG — это текст, поэтому его можно либо закодировать в Base64 (с ;base64), либо URL-кодировать (без). URL-кодированный SVG обычно меньше по объёму.
image/x-icon или image/vnd.microsoft.icon — favicon-ы. Base64 начинается с AAABAA.

<!-- All five types in a single HTML document -->
<img src="data:image/png;base64,iVBORw0KGgo..." alt="PNG inline">
<img src="data:image/jpeg;base64,/9j/4AAQSkZJRg..." alt="JPEG inline">
<img src="data:image/gif;base64,R0lGODlhAQABAA..." alt="GIF inline">
<img src="data:image/webp;base64,UklGRiIAAABXRU..." alt="WebP inline">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxu..." alt="SVG inline">

// ИСПОЛЬЗОВАНИЕ data: URI В HTML, CSS И JAVASCRIPT

Везде, где принимается URL, data URI работает так же.

<!-- HTML <img> tag -->
<img src="data:image/png;base64,iVBORw0KGgo..." width="32" height="32" alt="icon">

<!-- HTML <link> for favicon -->
<link rel="icon" href="data:image/x-icon;base64,AAABAAEAEBA...">

/* CSS background-image */
.button-icon {
  background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxu...');
  background-size: 16px 16px;
}

/* CSS @font-face — yes, fonts work too */
@font-face {
  font-family: 'InlineFont';
  src: url('data:font/woff2;base64,d09GMgAB...') format('woff2');
}

// JavaScript — assign directly to img.src
const img = new Image();
img.src = 'data:image/png;base64,iVBORw0KGgo...';
document.body.appendChild(img);

// JavaScript — fetch a data URI like any other URL
const response = await fetch('data:application/json;base64,eyJrZXkiOiJ2YWx1ZSJ9');
const data = await response.json(); // { key: 'value' }

// CANVAS, FILE И BLOB → data: URI

Три браузерных API отдают вам data URI без необходимости самому возиться с Base64:

// 1. Canvas → data URI (instant)
const canvas = document.querySelector('canvas');
const pngDataURI = canvas.toDataURL('image/png');
const jpegDataURI = canvas.toDataURL('image/jpeg', 0.85); // quality 0–1
// pngDataURI === 'data:image/png;base64,iVBORw0KGgo...'

// 2. <input type="file"> → data URI via FileReader
const file = document.querySelector('input[type=file]').files[0];
const reader = new FileReader();
reader.onload = () => {
  // reader.result is the data URI
  document.querySelector('img').src = reader.result;
};
reader.readAsDataURL(file);

// 3. Blob → data URI (manual, but rarely needed — use URL.createObjectURL instead)
const blob = new Blob([bytes], { type: 'image/png' });
const reader2 = new FileReader();
reader2.onload = () => console.log(reader2.result);
reader2.readAsDataURL(blob);
// Or, for in-page display, prefer:
const objectURL = URL.createObjectURL(blob); // 'blob:https://...' — much shorter, no Base64

// ШТРАФ В РАЗМЕРЕ 33% (И КОГДА ЭТО ВАЖНО)

Base64 превращает 3 байта бинарных данных в 4 ASCII-символа, поэтому закодированная полезная нагрузка имеет ровно 4⌈n/3⌉ байт — примерно на 33% больше оригинала. PNG в 12 КБ становится data URI размером ~16 КБ, плюс несколько байт накладных расходов на префикс data:image/png;base64,.

Когда это важно?
Крошечные ресурсы (до 4 КБ): 33% разрастания меркнут перед сэкономленным HTTP round-trip. Встраивайте смело.
Средние ресурсы (4–50 КБ): по ситуации. С HTTP/2 и кешированием отдельный запрос обычно быстрее, чем повторное скачивание встроенной версии при каждой загрузке страницы.
Большие ресурсы (50 КБ и выше): почти никогда не встраивайте. data URI раздувает каждую закешированную HTML-страницу, каждое письмо, каждую JSON-нагрузку, в которой он содержится. Используйте отдельный URL.

Для data URI нет кеширования — браузер не может закешировать изображение, байты которого впечатаны в HTML. Если одно и то же изображение встречается на нескольких страницах, каждая страница платит полную цену. Обычный <img src="/logo.png"> с заголовками HTTP-кеша скачивается один раз и переиспользуется везде.

// ОГРАНИЧЕНИЯ БРАУЗЕРОВ, С КОТОРЫМИ ВЫ СТОЛКНЁТЕСЬ

Браузеры не накладывают единого жёсткого ограничения на data URI, но реальные потолки существуют:

Chrome / Edge / Firefox: data URI в <img src> работают вплоть до нескольких мегабайт. За пределами ~32 МБ вы упрётесь в давление на память на уровне вкладки.
Safari: исторически ограничивал data URI в <a href> (ссылки на скачивание) примерно 2 МБ. Для <img> большие размеры работают, но рендеринг замедляется.
Internet Explorer 8: максимум 32 КБ для data URI в CSS и HTML. (IE9+ убрал это ограничение, но он никогда не был так быстр, как современные браузеры.)
HTTP request line: data URI в <form action> или query-строках ограничены длиной URL, которую принимает браузер (~2 КБ для IE, 8 КБ+ для остальных).

Если вы приближаетесь к любому из этих лимитов, ресурс слишком велик для встраивания. Переключитесь на обычный URL или на URL.createObjectURL(blob), который даёт короткий blob: URL, привязанный к blob, который вы держите в памяти.

// ВОПРОСЫ БЕЗОПАСНОСТИ

data URI работают без сети, что удобно — но они обходят несколько механизмов веб-безопасности, которые предполагают, что контент приходит с сервера.

Same-origin policy. data: URI технически считается opaque origin (в современных Chrome/Firefox), поэтому JavaScript, загруженный из data URI, не может неограниченно обращаться к cookie, localStorage или DOM родительского документа. Это хорошо для песочницы недоверенного контента, но также означает, что трекинг, аналитика и CSRF-защиты, опирающиеся на проверки origin, могут вести себя некорректно.

XSS через data:text/html. URL data:text/html,<script>...</script>, открытый пользователем, становится полноправной страницей. Современные браузеры по этой причине блокируют top-level навигацию на data:text/html (Firefox с 2018, Chrome с 2020). Не пропускайте предоставленные пользователем URL через любые редиректы, разрешающие схему data:.

Content Security Policy (CSP). По умолчанию строгие CSP блокируют data URI в img-src, style-src и т.д. Чтобы их разрешить, нужно явно указать data: в директиве (например, img-src 'self' data:). Будьте осознанны — разрешая data URI, вы также соглашаетесь на любое изображение (или шрифт), которое страница решит встроить.

Логи и PII. data URI — это часть URL. Любой логгер или аналитический инструмент, который захватывает URL (логи доступа сервера, история браузера, трекеры ошибок), захватит всю полезную нагрузку. Если ваш data URI содержит аватар, фото или скриншот пользователя, он окажется в ваших логах. Не помещайте PII в URL, которые вы не контролируете.

// data: URI VS. blob: URL — ЧТО ВЫБРАТЬ?

Оба позволяют отображать бинарные данные из памяти без загрузки на сервер. Выбор зависит от того, где данным нужно жить.

Используйте data: URI, когда данные должны быть переносимыми — встроены в HTML, отправлены в JSON, сохранены в БД, скопированы и вставлены в письмо. Данные — это и есть URL.

Используйте blob: URL, когда данные локальны и недолговечны — предварительный просмотр в SPA, триггер скачивания, изображение, исчезающее при закрытии страницы. URL.createObjectURL(blob) отдаёт вам короткий идентификатор (blob:https://example.com/12345-abcde), который браузер сопоставляет с blob-ом в памяти. Намного меньше, чем data URI, и можно отозвать через URL.revokeObjectURL(url) по завершении.

Правило большого пальца: если URL должен покинуть текущую страницу — используйте data:. Если он остаётся внутри страницы — используйте blob:.

// ТИПИЧНЫЕ ПРОБЛЕМЫ ПРИ ОТЛАДКЕ

Обрезанная строка из DevTools. Когда вы копируете длинный data URI из вкладки Network или панели Elements, браузеры часто обрезают значение многоточием. Отображаемый текст — это не полный URL. Чтобы получить полную строку, откройте исходный файл (CSS, HTML, JSON) напрямую, либо используйте в консоли document.querySelector('img').src — это вернёт полный URL.

Неверный MIME-тип. Полезная нагрузка PNG, помеченная как data:image/jpeg;base64,..., всё равно декодируется на байтовом уровне — Base64 не волнует MIME — но некоторые просмотрщики отвергают несоответствие. Реальный формат определяется магическими байтами (iVBORw0KGgo для PNG), поэтому при сомнениях вставьте полезную нагрузку в наш декодер Base64 в изображение; он автоматически определяет формат по байтам.

Отсутствующая запятая. Формат — data:image/png;base64,iVBORw..., а не data:image/png;base64;iVBORw.... Точка с запятой или отсутствующий разделитель делают весь URL недействительным.

URL-safe Base64 в data: URI. Стандартные data: URI используют стандартный алфавит Base64 (с + и /). Если ваша полезная нагрузка была закодирована в URL-safe варианте (RFC 4648 §5, с - и _), её нужно сконвертировать обратно перед встраиванием — см. наше руководство Base64 URL-safe vs Standard.

Пробельные символы внутри полезной нагрузки. Некоторые pretty-printer-ы переносят длинные Base64-строки на 76 столбцов с переносами строк. Большинство браузеров терпят это в <img src>, но некоторые (особенно старые WebView) — нет. Удаляйте пробелы перед встраиванием: str.replace(/\s+/g, '').

// КОГДА НЕ СТОИТ ИСПОЛЬЗОВАТЬ data: URI

Свыше 50 КБ. Цена сброса кеша + скачивания перевешивает сэкономленный запрос.
Повторяющиеся изображения. Всё, что используется более чем на одной странице, должно быть обычным URL с заголовками кеширования.
Публичная аналитика. Трекинг-пиксели, маяки и pixel-based attribution не сработают, потому что нет HTTP-запроса для логирования.
Контент, загруженный пользователем и отображаемый в SPA. Используйте URL.createObjectURL(blob) — он полностью избавляет от Base64-работы и примерно в 4 раза меньше по памяти.
Внутри среды со строгой CSP, не разрешающей data:. Не добавляйте data: в свою CSP только ради использования data URI; сначала спросите себя, действительно ли он вам нужен.

// 30-СЕКУНДНАЯ ШПАРГАЛКА

Формат: data:[mime-type][;base64],[payload]

Самая распространённая форма: data:image/png;base64,iVBORw0KGgo...

Декодировать обратно в изображение: вставьте в наш конвертер Base64 в изображение.

Закодировать изображение в data URI: используйте наш конвертер изображения в Base64 — он выдаёт полный data: URI, готовый к вставке.

Бюджет встраивания: < 4 КБ — встраивайте всегда, 4–50 КБ — зависит от ситуации, > 50 КБ — используйте обычный URL.

Браузерные API: canvas.toDataURL(), FileReader.readAsDataURL() или просто соберите строку сами: 'data:image/png;base64,' + btoa(binaryString).

Связанные материалы: встраивание изображений в Base64 · предварительный просмотр Base64-изображений в браузере · Base64 vs Base64URL vs Base32