Иногда бывает нужно создать ссылку, которая должна показать системный диалог для сохранения файла.
Браузеры достаточно умны, чтобы открыть этот диалог для некоторых двоичных файлов, например, для архивов или *.exe. Но что, если я хочу загрузить изображение или видео?
Заголовок Content-Disposition
Наиболее правильный способ — добавить заголовок Content-Disposition
на сервере:
Content-Disposition: attachment; filename=cat.jpg
Когда браузер встречает такой заголовок, он начинает скачивать файл, а не показывать его.
Но иногда вы не можете изменить конфигурацию сервера, поэтому нам нужен более браузерный способ решения проблемы.
Атрибут download
Самый простой способ сделать это — добавить атрибут download
к вашей ссылке.
Если вы добавите его без какого-либо значения, браузер попытается получить имя файла из заголовка Content-Disposition
(да, он имеет высокий приоритет) или из пути к нему.
<a href="cat.jpg" download>
<img src="cat-preview.jpg" alt="Cat photo preview">
</a>
You can set some value to download
if you want to change the default name. It can help when you have some strange auto-generated URL like https://cdn/images/a1H5-st42-Av1f-rUles
.
<a href="images/1h24v9lj.jpg" download="kitten"> Download</a>
Попробуйте: ссылка.
Важно! Вся эта магия атрибутов не предназначена для cross-origin ссылок. Вы не можете контролировать такие ссылки из-за проблем безопасности.
И помните, что IE и старый Safari ничего не знают про атрибут download
.
blob: и data:
Есть ещё один лайфхак, который поможет вашим пользователям сохранить фотографии котят в удобном для них формате. Если вы используете на своем сайте изображения в формате AVIF или WebP, велика вероятность, что никто не сможет сохранить их на своём компьютере или телефоне, чтобы просмотреть позже. Точнее, они смогут сохранить изображение, но не смогут его просмотреть. И это печально.
Чтобы помочь им, используйте data:
или blob:
URL-адреса внутри атрибута href
.
Шаг 1. Рисуем изображение при помощи canvas.
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const image = new Image();
image.onload = function () {
ctx.drawImage(image, 0, 0);
};
image.src = 'cat.avif';
Шаг 2a. Сохраняем изображение как blob
внутри атрибута href
.
const blobLink = document.getElementById('blob-link');
canvas.toBlob(
blob => {
const blobUrl = URL.createObjectURL(blob);
blobLink.href = blobUrl;
},
'image/jpeg',
0.9
);
Да, теперь я могу сохранить AVIF в формате JPEG. Круто, правда? Пользователь загрузит всего 4 КБ AVIF с сервера и получил свои 13 КБ в JPEG на клиенте!
Шаг 2b. Сохраняем изображение как data
в атрибуте href
ссылки.
Некоторые браузеры не могут использовать blob
, поэтому вы можете помочь им с помощью data-urls
.
const dataLink = document.getElementById('data-link');
dataLink.href = canvas.toDataURL('image/jpeg', 0.9);
Это еще проще, но не так эффективно.