Олег Марков
Атрибут download в HTML
Введение
Атрибут download в HTML позволяет подсказать браузеру, что по ссылке нужно не просто открыть ресурс, а скачать его как файл. Вы управляете поведением ссылки: вместо перехода на страницу или отображения картинки в браузере, файл попадает в папку загрузок пользователя.
Смотрите, я покажу вам, как это выглядит в самом простом варианте:
<!-- При клике браузер скачает файл example.pdf -->
<a href="files/example.pdf" download>Скачать инструкцию</a>Как видите, здесь мы просто добавили атрибут download к обычной ссылке. Но за этой простотой скрывается ряд особенностей: ограничения безопасности, поддержка браузерами, влияние кросс-доменных запросов, задание имени файла и работа с Blob-объектами.
В статье вы разберетесь:
- что именно делает атрибут download и в чем его отличие от обычной ссылки;
- как задавать собственное имя для скачиваемого файла;
- какие у атрибута есть ограничения (особенно при скачивании с другого домена);
- как сочетать download с JavaScript и Blob;
- какие практики стоит использовать, чтобы ссылки на скачивание работали предсказуемо.
Основы атрибута download
Что такое атрибут download
Атрибут download — это булевый атрибут тега <a>, который говорит браузеру: "эту ссылку нужно обрабатывать как скачивание файла". Проще говоря, при клике должен начаться процесс загрузки файла, а не открытие ресурса в текущей вкладке.
Базовый пример:
<a href="reports/2025-report.pdf" download>Скачать отчет за 2025 год</a>Комментарий:
<!--
href - путь к файлу, который нужно скачать
download - атрибут, говорящий браузеру инициировать загрузку
Текст ссылки - то, что пользователь увидит на странице
-->
<a href="reports/2025-report.pdf" download>Скачать отчет за 2025 год</a>Если вы не задаете значение атрибуту download (то есть просто пишете download без значения), браузер обычно использует имя файла из URL или из заголовка Content-Disposition (если сервер его задает).
Поддерживаемые теги
Атрибут download официально поддерживается у тега <a>. В спецификациях также встречается упоминание о <area>, но на практике это используется редко. Основной рабочий вариант — именно <a>.
Неправильно:
<!-- Атрибут download у button не сработает -->
<button download>Скачать</button>Правильно:
<a href="file.zip" download>Скачать</a>Значение атрибута download: без значения и с именем файла
Атрибут download можно использовать двумя способами:
- Без значения — просто как флаг.
- С текстовым значением — как имя сохраняемого файла.
Использование без значения
Если вы укажете download без значения, браузер:
- скачает ресурс по ссылке href;
- попытается использовать имя файла из URL;
- либо возьмет имя из заголовка Content-Disposition, если сервер его задаст.
Пример:
<a href="images/photo-2025.jpg" download>Скачать фото</a>Здесь браузер, как правило, сохранит файл под именем photo-2025.jpg.
Задание собственного имени файла
Если вы хотите контролировать имя загружаемого файла, можете указать значение атрибута download:
<a href="images/photo-2025.jpg" download="Отчетный-снимок.jpg">
Скачать фото как Отчетный-снимок.jpg
</a>Комментарии:
<!--
href - реальный путь к файлу на сервере
download="Отчетный-снимок.jpg" - имя файла, которое браузер предложит при сохранении
Текст ссылки - пояснение для пользователя
-->
<a href="images/photo-2025.jpg" download="Отчетный-снимок.jpg">
Скачать фото как Отчетный-снимок.jpg
</a>Важно понимать, что:
- значение download — это рекомендация для браузера;
- некоторые браузеры или настройки безопасности могут ее игнорировать;
- сервер может переопределить имя файла заголовком Content-Disposition (особенно при кросс-доменных запросах или строгих настройках).
Ограничения на название файла
В имени файла не стоит использовать:
- символы, которые недопустимы в файловой системе пользователя (например, в Windows:
? * : " < > |); - слишком длинные имена (некоторые системы могут обрезать их).
Безопаснее использовать:
- латиницу;
- цифры;
- дефисы и подчеркивания;
- при необходимости — символы национальных алфавитов, но с учетом возможных проблем в старых системах.
Пример более безопасного имени:
<a href="docs/report.pdf" download="otchet-2025.pdf">Скачать отчет</a>Поведение ссылок с download: навигация и вкладки
Взаимодействие с target
Атрибут target управляет тем, где откроется ссылка. download влияет на поведение скачивания, но target тоже играет роль.
Посмотрите несколько вариантов:
<!-- Скачивание в текущем окне -->
<a href="files/data.csv" download>Скачать CSV</a>
<!-- Скачивание с открытием новой вкладки (в некоторых браузерах сначала откроется вкладка, но скачивание все равно начнется) -->
<a href="files/data.csv" download target="_blank">Скачать CSV в новой вкладке</a>Комментарий:
<!--
target="_blank" - открывает ресурс в новой вкладке
download - инициирует загрузку файла
Результат - в большинстве браузеров файл скачается, а вкладка может быть пустой или кратко отобразить URL
-->
<a href="files/data.csv" download target="_blank">Скачать CSV в новой вкладке</a>Поведение с target="_blank" зависит от браузера. Иногда вы увидите новую вкладку, которая тут же закроется или останется пустой. Пользователь видит только скачивание файла.
Отличие от обычной ссылки без download
Для сравнения:
<!-- Без download - браузер попробует отобразить PDF в окне -->
<a href="docs/instruction.pdf">Открыть инструкцию</a>
<!-- С download - браузер начнет скачивание PDF -->
<a href="docs/instruction.pdf" download>Скачать инструкцию</a>Вы можете комбинировать подход:
- без download — "Открыть онлайн";
- с download — "Скачать файл".
Пример:
<a href="docs/instruction.pdf" target="_blank">Открыть инструкцию в браузере</a>
<a href="docs/instruction.pdf" download>Скачать инструкцию на компьютер</a>Ограничения безопасности и кросс-доменные запросы
Атрибут download подчиняется политике безопасности браузеров. Это сделано, чтобы вредоносные сайты не могли незаметно скачивать файлы с других ресурсов или насильно подменять их имена.
Поведение при скачивании с того же домена
Если ресурс расположен на том же домене (origin), что и страница, атрибут download обычно работает без ограничений:
<!-- origin: https://example.com -->
<a href="/files/report.pdf" download="report-2025.pdf">
Скачать отчет 2025
</a>В этом случае:
- браузер использует имя report-2025.pdf;
- файл скачивается без лишних предупреждений (если сервер не требует авторизации).
Поведение при скачивании с другого домена
Теперь давайте посмотрим, что происходит, если файл лежит на другом домене:
<!-- Страница на https://mysite.com -->
<a href="https://cdn.othersite.com/files/report.pdf" download="my-report.pdf">
Скачать отчет
</a>Многие браузеры в таком случае:
- игнорируют имя в download (my-report.pdf);
- используют имя, указанное сервером или взятое из URL;
- иногда могут вообще игнорировать атрибут download, если политика безопасности ресурса это запрещает.
Причина в том, что страница с одного домена не должна произвольно навязывать имена файлов с другого домена. Это может использоваться для фишинга и других атак.
Влияние заголовка Content-Disposition
Сервер может явно указать поведение файла с помощью заголовка Content-Disposition. Например:
Content-Disposition: attachment; filename="report.pdf"— сервер говорит: "это вложение, скачай его";Content-Disposition: inline— "попробуй отобразить в браузере".
Если сервер задает Content-Disposition, он может переопределить или усилить поведение, которое вы ожидаете от download.
Общая логика:
- если сервер говорит attachment, скачивание почти гарантировано, даже без download;
- если сервер inline, но вы установили download, браузер все равно обычно скачает файл;
- имя файла из Content-Disposition чаще всего приоритетнее, чем имя в download при кросс-доменных запросах.
Ограничения по протоколам
Атрибут download работает не для всех схем URL.
Как правило, он:
- работает для http и https;
- может игнорироваться для data: URL в некоторых браузерах;
- может не поддерживаться для file:, blob: и других схем в зависимости от реализации.
Смотрите пример с data URL:
<a href="data:text/plain,Hello%20world" download="hello.txt">
Скачать hello.txt
</a>Комментарии:
<!--
href - data URL с текстом Hello world
download="hello.txt" - желаемое имя файла
Поддержка - не во всех браузерах поведение предсказуемое
-->
<a href="data:text/plain,Hello%20world" download="hello.txt">
Скачать hello.txt
</a>Здесь часть браузеров корректно скачает файл, часть может попытаться открыть его в вкладке.
Атрибут download и JavaScript
Очень часто ссылки с download комбинируют с JavaScript: генерируют содержимое файла на лету, используют Blob-объекты, создают временные ссылки.
Программное создание ссылки с download
Покажу вам, как это реализовано на практике, когда файл генерируется в браузере:
<button id="save">Скачать как файл</button>
<script>
// Находим кнопку
const button = document.getElementById('save');
button.addEventListener('click', () => {
// Здесь мы создаем текстовое содержимое файла
const text = 'Пример данных для сохранения\nСтрока номер два';
// Создаем Blob-объект на основе строки
const blob = new Blob([text], { type: 'text/plain;charset=utf-8' });
// Получаем временный URL для Blob-объекта
const url = URL.createObjectURL(blob);
// Создаем временную ссылку
const a = document.createElement('a');
a.href = url; // Указываем ссылку на Blob
a.download = 'example.txt'; // Имя сохраняемого файла
a.style.display = 'none'; // Скрываем ссылку от пользователя
// Добавляем ссылку в документ
document.body.appendChild(a);
// Программно кликаем по ссылке, чтобы инициировать скачивание
a.click();
// Удаляем ссылку из DOM
document.body.removeChild(a);
// Освобождаем URL, чтобы не держать лишнюю память
URL.revokeObjectURL(url);
});
</script>Как видите, download здесь используется уже из JavaScript-кода. Это стандартный прием для скачивания данных, созданных на стороне клиента.
Пояснения по шагам:
- Создаем Blob из строки.
- Получаем временный URL через URL.createObjectURL.
- Создаем элемент
<a>, задаем href на Blob и атрибут download с именем файла. - Добавляем ссылку в DOM, вызываем click и сразу удаляем.
- Освобождаем URL через URL.revokeObjectURL.
Управление именем файла через JS
Вы можете динамически задавать имя файла в зависимости от контекста:
function downloadJson(data, filenamePrefix) {
// Преобразуем объект в JSON
const json = JSON.stringify(data, null, 2);
// Формируем имя файла с префиксом и датой
const date = new Date().toISOString().slice(0, 10); // Например, 2025-11-25
const filename = `${filenamePrefix}-${date}.json`;
// Создаем Blob
const blob = new Blob([json], { type: 'application/json' });
const url = URL.createObjectURL(blob);
// Создаем ссылку
const a = document.createElement('a');
a.href = url;
a.download = filename; // Динамическое имя файла
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
// Пример вызова функции
downloadJson({ user: 'Ivan', age: 30 }, 'user-data');Комментарии:
// filenamePrefix - префикс в имени файла, например user-data
// new Date().toISOString().slice(0, 10) - формируем дату в формате YYYY-MM-DD
// filename - итоговое имя файла, например user-data-2025-11-25.json
// a.download = filename - устанавливаем имя сохраняемого файлаОсобенности работы с разными типами файлов
Файлы, которые браузер обычно открывает
Многие типы файлов браузеры умеют показывать прямо во вкладке:
- картинки (jpg, png, gif, webp);
- PDF;
- текстовые файлы (txt, json);
- иногда аудио и видео.
Если вы не используете download, клик по ссылке на такой файл, как правило, откроет его во вкладке.
С download картина меняется:
<!-- Открытие картинки во вкладке -->
<a href="images/photo.jpg">Показать фото</a>
<!-- Принудительное скачивание картинки -->
<a href="images/photo.jpg" download="photo-local.jpg">Скачать фото</a>Файлы, которые по умолчанию скачиваются
Есть типы файлов, которые почти всегда скачиваются:
- архивы (zip, rar, 7z);
- исполняемые файлы (exe, msi);
- многие бинарные форматы.
Для них download часто не добавляет нового поведения, но он может:
- повлиять на имя файла;
- сделать поведение более прогнозируемым между браузерами.
Практические примеры использования download
Загрузка нескольких версий одного ресурса
Допустим, у вас есть страница с документацией, и вы предлагаете пользователю скачать документ в нескольких форматах. Давайте разберемся на примере:
<h3>Скачать руководство пользователя</h3>
<ul>
<li>
<!-- PDF-версия -->
<a href="docs/manual.pdf" download="manual-ru.pdf">
PDF версия
</a>
</li>
<li>
<!-- DOCX-версия -->
<a href="docs/manual.docx" download="manual-ru.docx">
DOCX версия
</a>
</li>
<li>
<!-- Архив со всеми файлами -->
<a href="docs/manual-full.zip" download="manual-ru-full.zip">
Полный архив
</a>
</li>
</ul>Здесь вы явно задаете имена файлов для каждого формата, чтобы у пользователя не копились файлы с непонятными названиями вроде manual(1).pdf.
Кнопка "Сохранить как CSV" для таблицы
Смотрите, я покажу вам, как это реализовать, когда вам нужно сохранить данные таблицы в CSV прямо из браузера.
<table id="report">
<tr><th>Месяц</th><th>Доход</th></tr>
<tr><td>Январь</td><td>1000</td></tr>
<tr><td>Февраль</td><td>1500</td></tr>
</table>
<button id="download-csv">Скачать CSV</button>
<script>
// Функция преобразования таблицы в CSV
function tableToCsv(table) {
// Получаем строки таблицы
const rows = Array.from(table.querySelectorAll('tr'));
// Преобразуем каждую строку в CSV-формат
const csvLines = rows.map(row => {
const cells = Array.from(row.querySelectorAll('th, td'));
return cells
.map(cell => {
const text = cell.textContent.trim();
// Экранируем запятые и кавычки
const escaped = text.replace(/"/g, '""');
return `"${escaped}"`;
})
.join(',');
});
// Соединяем строки через перевод строки
return csvLines.join('\n');
}
document.getElementById('download-csv').addEventListener('click', () => {
const table = document.getElementById('report');
// Получаем CSV-строку
const csv = tableToCsv(table);
// Создаем Blob с типом text/csv
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' });
const url = URL.createObjectURL(blob);
// Создаем ссылку с атрибутом download
const a = document.createElement('a');
a.href = url;
a.download = 'report.csv'; // Имя файла
// Добавляем, кликаем, удаляем
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
// Освобождаем URL
URL.revokeObjectURL(url);
});
</script>Комментарии:
// tableToCsv - превращает DOM-таблицу в CSV-текст
// new Blob([csv], { type: 'text/csv;charset=utf-8' }) - создаем Blob с типом CSV
// a.download = 'report.csv' - задаем имя сохраняемого файла
// a.click() - инициируем скачивание без участия пользователя в DOMАдаптация под разные браузеры
Поддержка атрибута download
Современные версии основных браузеров (Chrome, Firefox, Edge, Safari, Opera) поддерживают атрибут download, но есть нюансы:
- старые версии Internet Explorer его не поддерживают;
- в старых мобильных браузерах поведение может отличаться.
Если вам важно покрыть старые браузеры, стоит:
- использовать серверный заголовок Content-Disposition: attachment;
- дублировать функциональность через JavaScript (Blob, window.location и прочее) там, где это уместно.
Падение обратно на обычное поведение
Хорошая новость: если браузер не понимает download, ссылка просто ведет себя как обычная:
<a href="docs/manual.pdf" download>Скачать руководство</a>В старом браузере пользователь, скорее всего, увидит PDF во вкладке и сам нажмет "Сохранить как" через интерфейс браузера. То есть деградация функциональности происходит мягко.
Сочетание с серверной логикой
Когда лучше полагаться на сервер
Атрибут download удобен, но он работает только на стороне клиента. В некоторых случаях вам нужно управлять скачиванием с сервера:
- авторизованный доступ к файлам;
- логирование скачиваний;
- ограничение числа скачиваний;
- выдача разных версий файла в зависимости от параметров.
В таких сценариях обычно:
- На клиенте вы по-прежнему используете download, чтобы подсказать браузеру поведение.
- На сервере вы настраиваете заголовки и логику выдачи.
Пример HTTP-ответа от сервера (упрощенно, псевдокод):
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="manual-ru.pdf"
<тело PDF-файла>Комментарии:
Content-Type - тип содержимого (здесь PDF)
Content-Disposition - attachment - указание браузеру скачать файл как вложение
filename="manual-ru.pdf" - рекомендуемое имя файлаДаже без download браузер скачает такой файл, так как сервер явно требует поведение attachment.
Совмещение Content-Disposition и download
Как правило:
- для внутренних файлов (на том же домене) вы можете ограничиться атрибутом download;
- для более строгого контроля лучше дублировать поведение заголовком Content-Disposition.
Пример HTML + серверной настройки:
<a href="/download/manual/ru" download="manual-ru.pdf">
Скачать руководство на русском
</a>На сервере по маршруту /download/manual/ru:
- проверяется авторизация;
- выбирается нужный файл;
- отправляется ответ с Content-Disposition: attachment; filename="manual-ru.pdf".
Если какой-то браузер проигнорирует download, заголовок все равно заставит его скачать файл.
Ограничения и подводные камни
Нельзя обойти диалоги безопасности браузера
Атрибут download не может:
- автоматически сохранять файл без участия пользователя;
- обходить системные диалоги сохранения;
- отключать проверки безопасных загрузок.
Пользователь в любом случае контролирует, куда и что сохранять.
Не всегда удается переименовать файл
Даже если вы указали download="myname.ext":
- браузер может изменить имя файла (например, добавить (1), (2) при дубликатах);
- сервер может задать другое имя через Content-Disposition;
- для кросс-доменных ресурсов имя может быть проигнорировано.
Поэтому download — это не гарантия имени файла, а лишь рекомендация.
Не стоит использовать для конфиденциальных файлов без сервера
Если вы генерируете конфиденциальные данные на клиенте и даете их скачивать через download, помните:
- пользователь может сохранить файл где угодно;
- браузер может кэшировать содержимое;
- вы не контролируете дальнейшее использование.
Для реальной защиты конфиденциальных документов обычно используют:
- авторизацию;
- шифрование;
- ограничение времени действия ссылки.
Атрибут download тут не отвечает за безопасность.
Заключение
Атрибут download в HTML — это простой, но полезный инструмент, который позволяет управлять поведением ссылок при скачивании файлов. Вы можете:
- явно сказать браузеру "скачать, а не открыть";
- задать читаемое имя для загружаемого файла;
- комбинировать атрибут с JavaScript и Blob, чтобы сохранять данные, сгенерированные на стороне клиента.
При этом важно учитывать:
- ограничения безопасности при кросс-доменных запросах;
- взаимодействие с заголовком Content-Disposition;
- возможные различия в поведении браузеров.
Если вы строите систему скачивания файлов, старайтесь сочетать download с корректной серверной конфигурацией и, при необходимости, с JavaScript-логикой. Тогда пользователи получат предсказуемое поведение, а вы — больше контроля над тем, как именно загружаются ваши ресурсы.
Частозадаваемые технические вопросы по теме и ответы
Как реализовать скачивание файла по POST-запросу, если download работает только с ссылками?
Атрибут download действительно применяется к <a> и работает по GET-запросу. Чтобы инициировать скачивание по POST, используйте один из подходов:
- Отправляете POST из формы на сервер, сервер в ответ возвращает файл с заголовком Content-Disposition: attachment. Тогда браузер начнет скачивание сам.
- Либо:
- отправляете POST через fetch;
- получаете Blob;
- создаете временный URL и ссылку с download (как в примерах выше);
- программно кликаете по ссылке.
Мини-инструкция (fetch + Blob):
fetch('/export', {
method: 'POST',
body: JSON.stringify({ filter: 'today' }),
headers: { 'Content-Type': 'application/json' }
})
.then(res => res.blob())
.then(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'export.csv';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
});Почему ссылка с download открывает PDF во вкладке, а не скачивает?
Основные причины:
- сервер явно задает
Content-Disposition: inline, и браузер следует ему; - браузер или расширение принудительно открывает PDF во встроенном просмотрщике;
- вы используете кросс-доменный ресурс, и браузер игнорирует download.
Что можно сделать:
- На сервере установить
Content-Disposition: attachment. - Проверить настройки браузера и отключить автопросмотр PDF (если это допустимо).
- Использовать собственный сервер-проксирование, чтобы выдавать PDF с вашего домена с нужными заголовками.
Можно ли принудительно задать расширение файла через download, если у URL его нет?
Да, вы можете задать любое имя, включая расширение, в значении download:
<a href="/api/report" download="report-2025.xlsx">Скачать отчет</a>Но важно:
- расширение не меняет фактический формат данных;
- если сервер вернет не Excel-файл, а, например, PDF, пользователь получит файл с расширением xlsx, который не откроется корректно.
Лучше обеспечивать согласованность: сервер выдает правильный тип, а вы задаете соответствующее расширение.
Как сделать, чтобы файл скачивался только после авторизации, но download при этом работал?
Используйте защиту на стороне сервера:
- Ссылка ведет на защищенный URL, например
/secure/files/report.pdf. - На сервере маршрут
/secure/files/report.pdfпроверяет авторизацию пользователя:- если пользователь не авторизован — редирект на логин или ошибка 401/403;
- если авторизован — выдается файл с Content-Disposition: attachment.
- На клиенте вы можете добавить download, чтобы подсказать браузеру поведение:
<a href="/secure/files/report.pdf" download="report-2025.pdf">
Скачать отчет 2025
</a>Таким образом, доступ контролируется сервером, а download улучшает UX.
Почему download не работает для blob: URL в некоторых старых браузерах?
Поддержка download для blob: URL появилась не сразу и не во всех браузерах одновременно. В старых версиях:
- атрибут download может игнорироваться для blob: ссылок;
- программный клик по
<a>может не вызывать скачивание.
Обходной путь:
- использовать библиотеку, которая учитывает особенности конкретных браузеров (например, старые версии FileSaver.js);
- проверять поддержку: если атрибут download есть у
HTMLAnchorElement.prototype, использовать стандартный путь, если нет — применять альтернативы (например,navigator.msSaveOrOpenBlobв старом Edge/IE).
Постройте личный план изучения Html до уровня Middle — бесплатно!
Html — часть карты развития Frontend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Все гайды по Html
Лучшие курсы по теме

HTML и CSS
Антон Ларичев
TypeScript с нуля
Антон Ларичев