Data URI scheme: встраивание ресурсов в HTML
Data URI для изображений, шрифтов, SVG. Преимущества и недостатки, когда использовать, оптимизация.
Введение
Каждая веб-страница обычно состоит из одного HTML-файла и десятка внешних ресурсов: изображения, шрифты, иконки, аудио. Каждый внешний ресурс — это отдельный HTTP-запрос, который увеличивает время загрузки. Но есть способ встраивать ресурсы прямо в HTML или CSS, без отдельных запросов: это Data URI scheme. В статье разберём, что это такое, как использовать, когда выгодно и какие есть подводные камни.
Для конвертации изображений в Data URI используйте наши инструменты: изображение в Base64 и Base64 в изображение.
Что такое Data URI
Data URI (или data URL) — это схема URI, которая позволяет встраивать небольшие ресурсы прямо в документ в виде строки. Синтаксис описан в RFC 2397 и выглядит так:
data:[<mediatype>][;base64],<data>Где:
mediatype— MIME-тип данных (например,image/png,text/plain,application/json); по умолчаниюtext/plain;charset=US-ASCII;base64— необязательный флаг, указывающий, что данные закодированы в Base64data— собственно данные
Простейший пример — текстовый фрагмент:
data:text/plain;base64,SGVsbG8sIOSJa2EhЕсли вставить это в адресную строку браузера, откроется страница с текстом «Hello, юзер!».
Синтаксис и примеры
Текстовые данные без Base64
Если MIME-тип текстовый и не содержит специальных символов, можно вставить данные напрямую, без Base64. Но все небезопасные символы нужно URL-кодировать (см. статью о URL кодировании):
data:text/plain,Hello%2C%20World!Изображение PNG в Base64
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==" alt="пиксель 1x1">Это пример встраивания изображения размером 1×1 пиксель. На таком размере Data URI работает идеально: один файл, один запрос, мгновенная загрузка.
SVG прямо в HTML
SVG — текстовый формат, поэтому его можно встраивать без Base64, прямо как URL-encoded строку:
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='50' r='40' fill='red'/%3E%3C/svg%3E" alt="красный круг">Или, что чаще применяется, в виде отдельного тега <svg> прямо в HTML. Но если SVG нужно использовать в CSS-свойстве background или какsrc изображения, Data URI — подходящий вариант.
Шрифт в CSS
@font-face {
font-family: 'MyFont';
src: url(data:font/woff2;charset=utf-8;base64,d09GMgABAAAAAA...) format('woff2');
font-weight: normal;
font-style: normal;
}Встраивание шрифтов через Data URI позволяет избежать дополнительных запросов и гарантирует, что шрифт загрузится вместе с CSS. Но файл шрифта часто весит десятки килобайт, и встроенный CSS становится громоздким.
JSON в Data URI
data:application/json,{"name":"Иван","age":30}Когда использовать Data URI
1. Маленькие иконки и декоративные элементы
Иконки размером до 1–2 КБ — идеальный кандидат для Data URI. Встраивание экономит HTTP-запрос и не сильно раздувает HTML. Если иконок много, можно объединить их в спрайт, но для редких декоративных элементов Data URI удобнее.
2. Письма (HTML email)
В email-клиентах нельзя использовать JavaScript, а многие из них блокируют внешние изображения по умолчанию. Встраивание логотипа или иконок через Data URI (или CID) — способ показать их сразу, без запросов к серверу.
3. Standalone HTML-файлы
Если нужно передать один HTML-файл, который должен работать без интернета (например, отчёт или документация), встраивание всех ресурсов через Data URI делает его полностью автономным.
4. Уменьшение задержки при загрузке
Каждый HTTP-запрос — это задержка на установку соединения, отправку заголовков и ожидание ответа. Для маленьких ресурсов эта задержка может быть больше, чем время передачи самих данных. Data URI убирает её полностью.
5. Динамически генерируемые изображения
Если изображение генерируется на стороне клиента (например, через canvas), его можно сразу показать через Data URI без загрузки на сервер.
const canvas = document.createElement('canvas');
canvas.width = 100;
canvas.height = 100;
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, 100, 100);
const dataUri = canvas.toDataURL('image/png');
// "data:image/png;base64,iVBORw0KGgo..."
const img = document.createElement('img');
img.src = dataUri;
document.body.appendChild(img);Когда НЕ стоит использовать Data URI
1. Большие изображения
Каждое изображение в Data URI увеличивается на ~33% из-за Base64. Для фотографии в 200 КБ это значит +66 КБ. Кроме того, браузер не кеширует Data URI отдельно от страницы, поэтому при каждом заходе пользователя картинка загружается заново.
2. Часто меняющиеся ресурсы
Если встроенное изображение меняется, придётся перезагружать всю страницу. Внешний ресурс можно обновить независимо, и браузер закеширует его новую версию.
3. Ресурсы, которые нужны не на всех страницах
Внешний CSS или шрифт, подключённый через <link>, кешируется и не загружается повторно при переходе между страницами. Data URI каждый раз загружается вместе с HTML.
4. SVG с анимацией или интерактивом
SVG, вставленный через Data URI в атрибут src, не поддерживает интерактивные элементы и анимации так же гибко, как inline-SVG. Если нужны JavaScript-обработчики внутри SVG — вставляйте его прямо в HTML.
Преимущества и недостатки
| Преимущества | Недостатки |
|---|---|
| Нет дополнительных HTTP-запросов | Рост размера данных на ~33% (Base64) |
| Автономный HTML-файл | Невозможность независимого кеширования |
| Простота использования в email | Увеличение размера HTML-файла |
| Мгновенная загрузка маленьких ресурсов | Проблемы с большими файлами |
| Поддержка всех современных браузеров | Ограничения в IE8 и старше |
| Удобство для динамически создаваемых изображений | Не индексируется поисковиками как отдельный ресурс |
Размер и ограничения
Data URI увеличивает размер ресурса примерно на 33% из-за Base64. Это плата за представление бинарных данных как текста. Подробнее о Base64 — в статье о Base64 кодировании.
Исторически у браузеров были ограничения на размер Data URI. Например, IE8 не поддерживал Data URI длиннее 32 КБ. Современные браузеры таких ограничений не имеют, но здравый смысл подсказывает: если ресурс больше 10–20 КБ, лучше использовать отдельный файл.
| Размер ресурса | Рекомендация |
|---|---|
| До 1 КБ | Data URI — оптимально |
| 1–10 КБ | Data URI разумно, особенно для иконок |
| 10–50 КБ | Сомнительно: рассмотрите внешние файлы |
| 50–200 КБ | Лучше внешний файл с кешированием |
| Более 200 КБ | Обязательно внешний файл |
Кеширование и Data URI
Главное архитектурное отличие Data URI от обычных ссылок — поведение кеша. Внешний ресурс кешируется отдельно и переиспользуется на всех страницах сайта. Data URI встраивается в каждый HTML или CSS файл и не кешируется независимо.
Это значит, что если у вас 100 страниц и на каждой встроена одна и та же иконка в 1 КБ, общий объём переданных данных составит 100 КБ, а не 1 КБ. Для маленьких ресурсов это окупается экономией на HTTP-запросах, для больших — нет.
Решение: используйте Data URI только для уникальных ресурсов или очень маленьких иконок. Для повторяющихся на многих страницах ресурсов — внешние файлы с правильными заголовками кеша.
Безопасность и Data URI
1. Фишинг через Data URI
Атакующий может встроить в Data URI страницу, имитирующую форму входа, и отправить жертве ссылку. Поскольку Data URI не имеет домена, пользователь не видит настоящий адрес. Современные браузеры частично решают эту проблему, отображая «data:» в адресной строке и блокируя навигацию верхнего уровня на Data URI.
2. CSP и встроенные ресурсы
Content Security Policy (CSP) по умолчанию блокирует встроенные ресурсы. Чтобы разрешить Data URI, нужно явно указать data: в директиве img-src или аналогичной:
Content-Security-Policy: default-src 'self'; img-src 'self' data:;3. XSS через SVG
SVG-файл может содержать JavaScript. Если вы встраиваете SVG через Data URI в тег<img>, скрипты не выполняются. Но если через <iframe> или <embed> — выполняются. Будьте осторожны с пользовательскими SVG-файлами. Подробнее о XSS-защите — в статье об HTML сущностях.
Генерация Data URI в JavaScript
// Из строки
function textToDataUri(text, mimeType = 'text/plain') {
const base64 = btoa(unescape(encodeURIComponent(text)));
return `data:${mimeType};base64,${base64}`;
}
textToDataUri('Привет, мир!', 'text/plain');
// "data:text/plain;base64,D0/fgD8PfgD8PfgD8PfgD8PfgD8PfgD8PfgD8PfgD8PfgD8"
// Из файла (через FileReader)
function fileToDataUri(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(file);
});
}
// Использование
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', async () => {
const dataUri = await fileToDataUri(input.files[0]);
console.log(dataUri);
});Генерация Data URI в Node.js
import fs from 'fs';
function fileToDataUri(path, mimeType) {
const buffer = fs.readFileSync(path);
const base64 = buffer.toString('base64');
return `data:${mimeType};base64,${base64}`;
}
const dataUri = fileToDataUri('logo.png', 'image/png');Генерация Data URI в Python
import base64
def file_to_data_uri(path, mime_type):
with open(path, 'rb') as f:
data = base64.b64encode(f.read()).decode('ascii')
return f'data:{mime_type};base64,{data}'
data_uri = file_to_data_uri('logo.png', 'image/png')Оптимизация: что ещё можно сделать
1. Используйте WebP или AVIF вместо PNG
Современные форматы изображений WebP и AVIF сжимают лучше, чем PNG и JPEG. Если встраиваете изображения через Data URI, используйте WebP или AVIF — размер Base64-строки будет меньше. Подробнее — в наших статьях о WebP и об AVIF.
2. Минимизируйте SVG перед встраиванием
SVG — это XML, и его можно минимизировать: удалить комментарии, лишние пробелы, оптимизировать пути. Используйте инструменты вроде SVGO. Подробнее — в статье о минификации.
3. Сжатие на сервере
HTML с Data URI хорошо сжимается gzip или brotli. Базовый прирост размера от Base64 (33%) частично компенсируется сжатием, особенно для текстовых ресурсов вроде SVG.
4. Ленивая загрузка
Если Data URI используется в CSS для фоновой картинки, можно применять lazy loading через IntersectionObserver, подставляя Data URI только когда элемент попадает в зону видимости.
Альтернативы Data URI
HTTP/2 Server Push
Сервер может «протолкнуть» ресурсы вместе с HTML, не дожидаясь запроса от браузера. Это даёт эффект, похожий на Data URI, но без увеличения размера HTML. Однако Server Push сложно настроить корректно, и в HTTP/3 от него отказались.
HTTP/2 multiplexing
В HTTP/2 несколько запросов мультиплексируются в одном TCP-соединении, что снижает накладные расходы на каждый запрос. С HTTP/2 преимущество Data URI в количестве запросов становится менее значимым.
Service Worker с Cache API
Service Worker может кешировать ресурсы и отдавать их мгновенно. Это даёт эффект встраивания (нет задержки на сеть), но с правильным кешированием.
SVG sprite
Для иконок эффективнее SVG-спрайт: один SVG-файл со всеми иконками, на которые ссылаются через <use>. Это даёт кеширование и небольшое количество запросов.
Заключение
Data URI — удобный инструмент для встраивания маленьких ресурсов прямо в HTML или CSS. Он сокращает количество HTTP-запросов, делает HTML-файлы автономными и незаменим в email-вёрстке. Но у него есть цена: рост размера данных на 33% и отсутствие независимого кеширования. Используйте Data URI с умом — для маленьких иконок, декоративных элементов и автономных файлов, но избегайте для больших изображений и часто меняющихся ресурсов.
Для конвертации изображений в Data URI используйте наши инструменты: изображение в Base64 и Base64 в изображение. А если хотите лучше понять, как Base64 работает «под капотом» — читайте нашу статью о Base64 кодировании.
Попробуйте эти инструменты
Похожие статьи
Base64 — что это и как работает
Принцип кодирования Base64, алфавит, padding, использование в Data URI, email, API. Примеры кодирования.
URL кодирование: percent-encoding explained
Что такое URL encoding, зарезервированные символы, как кодировать/декодировать URL, частые ошибки.
HTML сущности и кодирование спецсимволов
HTML entities, named vs numeric, XSS защита, кодирование кавычек, амперсандов, угловых скобок.
JWT токен: структура и как декодировать
JSON Web Token: header, payload, signature. Как работает аутентификация JWT, безопасность, декодирование.