The semantics inherent in HTML elements tell us what we’re supposed to use them for. Need a heading? You’ll want a heading element. Want a paragraph? Our trusty friend <p>
is here, loyal as ever. Want a download? Well, you’re going to want… hmm.
What best describes a download? Is it a triggered action, and therefore should be in the domain of the <button>
element? Or is it a destination, and therefore best described using an <a>
element?
Buttons Do Things, Links Go Places
There seems to be a lot of confusion over when to use buttons and when to use links. Much like tabs versus spaces or pullover hoodies versus zip-ups, this debate might rage without end.
However, the W3C provides us with an important clue as to who is right: the download
attribute.
The What Now?
The internet as we know it couldn’t exist without links. They form the Semantic Web, the terribly wonderful, wonderfully terrible tangled ball of information that enables you to read this article at this very moment.
Like all other elements, anchor links can be modified by HTML’s global attributes. Anchor link elements also possess a number of unique attributes that help control how they connect to other documents and files.
One of those attributes is called download
. It tells the browser that the destination of the link should be saved to your device instead of visiting it. You’re still “navigating” to the file, only instead of viewing it, you’re snagging a copy for your own use.
Any kind of file can be a download! This even includes HTML, something the browser would typically display. The presence of the attribute is effectively a human-authored flag that tells the browser to skip trying to render something it has retrieved and just store it instead:
<a download href="recipe.html">
Download recipe
</a>
This raises a very important point: we can’t know every user’s reason for why they’re visiting our website, but we can use the tools made available to us to help guide them along their way. If that means storing an HTML document for use offline, we’re empowered to help make the experience as easy as possible.
Other Evidence
Still not convinced? Here’s some more food for thought:
Progressive Enhancement
JavaScript is more brittle than we care to admit. <a>
elements function even if JavaScript breaks. Using anchors for your download means that a person can access what they need, even in suboptimal situations.
A robust solution is always the most desirable—in a time of crisis, it might even save a life. This might sound hyperbolic, but having a stable copy of something that works offline could make all the difference in a time of need.
Semantics and Accessibility
My friend Scott, who is paid to know these kinds of things, tells us:
The debate about whether a button or link should be used to download a file is a bit silly, as the whole purpose of a link has always been to download content. HTML is a file, and like all other files, it needs to be retrieved from a server and downloaded before it can be presented to a user.
The difference between a Photoshop file, HTML, and other understood media files, is that a browser automatically displays the latter two. If one were to link to a Photoshop
.psd
file, the browser would initiate a document change to render the file, likely be all like, “lol wut?” and then just initiate the OS download prompt.The confusion seems to come from developers getting super literal with the “links go places, buttons perform actions.” Yes, that is true, but links don’t actually go anywhere. They retrieve information and download it. Buttons perform actions, but they don’t inherently “get” documents. While they can be used to get data, it’s often to change state of a current document, not to retrieve and render a new one. They can
get
data, in regards to the functionality ofform
s, but it continues to be within the context of updating a web document, not downloading an individual file.Long story short, the
download
attribute is unique to anchor links for a reason.download
augments the inherent functionality of the link retrieving data. It side steps the attempt to render the file in the browser and instead says, “You know what? I’m just going to save this for later…”
Thanks, Scott!
Designing a Good Download Link
The default experience of downloading a file can be jarring—it typically isn’t part of our normal browsing behavior. The user has to shift their mental model from flitting from page-to-page and filling out forms to navigating a file system and extracting compressed archives. For less technologically-savvy individuals, it can be a disorienting and frustrating context shift.
As responsible designers and developers, we want to make the experience of interacting with a download link as good as it possibly can be. As we can’t modify how the browser’s download behavior itself operates, we should make the surrounding user experience as transparent and streamlined as possible.
Tell Me What’s in Store
Give the user as much information as you can to help inform them on what’s about to happen. Anticipating and answering the following questions can help:
What?
Verb plus noun is the winning combination. Describe what the link does and what it gets you:
<a download href="downloads/fonts.zip">
Download Fonts
</a>
By itself, the verb Download would only signal what behavior will be triggered when the link is activated. Including the noun Fonts is great for removing ambiguity about what you’ll be getting.
In cases where there’s multiple download links on a page, the presence of the noun will help users navigating via screen reader. Here’s what it would sound like if you were browsing a page that had eight noun-less download links:
Do you know which one of those eight links gets you what you want? No? That’s not great. Similarly, the presence of the download
attribute on an <a>
element won’t be announced by screen readers, so the verb is equally vital. It’s important to provide context!
Remember that obvious always wins. While it is possible to make your compliance checks happy by using a visually hidden CSS class to hide the noun portion of your download, it places extra cognitive burden on your users. A hidden noun also sacrifices functionality like the browser’s search-on-page capability.
How Long?
KB, MB, GB, TB. We’re not talking about Kobe Beef, Mega Bloks, Ginkgo Biloba, or Tuberculosis. We’re talking about the size of the download, and consequently how long it will take for the download to finish.
Know your audience. A file with a size of 128 KB will download much faster than a file with a size of 2 GB, yet its number is drastically larger. Unless your audience has familiarity with the terminology used to describe file size, they may not understand what they’re getting themselves into if you only tell them the size of the payload.
For larger files, the wait time can be especially problematic. A standard download is an all-or-nothing affair—interruptions can corrupt them and render them useless. Worse, it can waste valuable data on a metered data plan, an unfortunately all-too-relevant concern.
It is also incredibly difficult to accurately ascertain someone’s current connection speed. While the Network Information API looks promising, current browser support isn’t so hot.
There is hidden nuance living in the gap between reported and actual connection. A high speed 5G connection could drop the second someone enters a tunnel or walks to a spot in their house where coverage isn’t good. This isn’t even beginning to cover the complexities involved with throttling, an unfortunately all-too-real concern.
To address these issues, apply a little micro-copy:
See the Pen Download movie by Eric Bailey (@ericwbailey) on CodePen.
Your user is going to know the particulars of their connection quality better than you ever will. Now they have what they need to make an informed decision, with a little intentional ambiguity to temper expectations.
But what about progress bars?
Progress bars are UI elements that show how close a computational task is to completion. For UX designers, they’re a staple (and an opportunity to play around with perceived performance). However, I’m wary of employing them when it comes to downloads.
At best, they’re redundant. Browsers already supply UI to indicate how the download is progressing. At worst, they’re a confusing liability. Adding them introduces unnecessary implementation and maintenance complications—especially when combined with the issues in determining connection speed and quality outlined earlier.
Why?
Sell the user on why they should care. Will it remove frustration by fixing an existing problem? Will it increase enjoyment by adding a new feature? Will it reassure by making things more secure? While not every download needs the “why?” question answered, it is good to have for payloads with a complicated or esoteric purpose.
If I am downloading router firmware, I may not understand (or care about) the nitty-gritty of what the update does behind the scenes. However, some high-level communication about why I need to undertake the endeavor will go a long way.
See the Pen Describe what the download does by Eric Bailey (@ericwbailey) on CodePen.
What Next?
Instructions on what to do after the download has completed could be useful. Again, knowing your audience is key.
With our router example, it is entirely possible that less technically-savvy individuals will find themselves on the product support page. It’s also highly possible that they’re in a distressed emotional state when they arrive. After a download has been initiated, step-by-step information on how to install the new firmware, as well as links to relevant support resources could go a long way to alleviating negative feelings.
This is practical empathy. Anticipating the user’s needs and emotional state and preemptively offering solutions has a direct effect on things like reducing expensive support calls. These savings means organizational resources can be reallocated to other important endeavors.
Taking it to Code
Signal That it’s Different
A good practice from both a user experience and an accessibility perspective is to create a distinction between internal and external links. This means creating an indicator that a link does something other than take you to another place on your website or webapp. For links that go off-site, a common practice is to use an arrow breaking out of a box. For downloads, a downward-facing arrow is the de facto standard.
Some may feel that the presence of the download
attribute is redundant when applied to links the browser already knows to store. I disagree.
In addition to being an unambiguous semantic marker in the HTML, the download
attribute can serve as a simple and elegant styling hook. CSS attribute selectors—code that lets us create styling based on the qualities that help describe HTML elements—allow us to target any link that is a download and style it without having to attach a special class:
a[download] {
color: hsla(216, 70%, 53%, 1);
text-decoration: underline;
}
a[download]::before {
content: url('../icons/icon-download.svg');
height: 1em;
position: relative;
top: 0.75em;
right: 0.5em;
width: 1em;
}
a[download]:hover,
a[download]:focus {
text-decoration: none;
}
Combined with the text describing the download, the presence of the icon clearly communicates that when you activate this link, download behavior will follow. It also provides extra target area, great for touch devices.
Targeting both the presence of the download
attribute and the file extension at the end of the string in the href
attribute allows us to get even fancier. We can take advantage of the cascade to set up a consistent treatment for all icons, but change the icon itself on a per-filetype basis. This is great for situations where there are multiple kinds of things you can download on a single page:
See the Pen Download icons by Eric Bailey (@ericwbailey) on CodePen.
I maintain a list of common filetypes, if you’re looking for a starting point. Remember to only include the selectors you need, so as to not create unnecessary bloat in your production CSS. If your website or webapp features many icons and/or a lot of fancy state management, consider using a SVG icon system instead. It will improve performance—just remember to make it accessible!
Name the Payload
The download
attribute can accept an optional value, allowing the author to create a custom, human-friendly name for the downloaded file. In this example, we’re changing the name of a podcast episode to something that makes sense when downloaded to the user’s device, while maintaining something that makes sense to the podcast’s producer:
<a
download="Pod-People-Podcast-Episode-12-Feed-Me-Seymour.mp3"
href="https://www.dropbox.com/s/txf5933cwxhv1so6/12-final-v5-RADIO-EDIT.m4a?dl=0">
Download Episode 12
</a>
For complicated sites, this attribute allows us to create downloads that make sense to the person requesting them, while also taking advantage of features like CDNs and dynamically-generated files. Not a lot of complicated backend sorcery here, just a little template logic:
<a
href="https://s3-us-west-2.amazonaws.com/ky22o6s6g8be80bak577b17e34bb93cex3.pdf"
download="{{ user.name | slugify }}-{{ 'now' | date: "%Y" }}-tax-return.pdf">
Download your {{ 'now' | date: "%Y" }} Tax Return
</a>
Material Honesty
Keeping content looking and behaving like the HTML elements used to describe it is great for reinforcing external consistency. Externally consistent content is great for ensuring people can, and will use your website or webapp. Use is great for engagement, a metric that makes business-types happy.
And yet, link-y buttons and button-y links are everywhere.
We can lay blame for this semantic drift squarely at the feet of trend. Designers and developers eager to try the latest and greatest invite ambiguity in with outstretched arms. Leadership chases perceived value to stay relevant.
It doesn’t have to be this way. Websites can be both beautiful and accessible. Semantics and current frameworks/aesthetics aren’t mutually exclusive. Take a little time to review the fundamentals—you just might discover something simple that helps everyone get what they need with just a little bit less fuss.
The download attribute, unfortunately, is sometimes ignored.
I had a situation where I wanted to download several images from a webpage. I created a userscript to accomplish this. I gathered the images using
document.querySelectorAll
, and then created an invisible a tag like<a download href="imgsrc">
, and then programmatically clicked each of those links.The script worked perfectly in Chrome (prompting me if I really wanted to allow multiple downloads), but when I tried the same script in Firefox, all it did was open the last image inside the browser. Firefox decided that since it could render the image, it would display it rather than download it.
However, a similar userscript I wrote to download some json data, which generated a tag like
<a download="data.json" href="data:application/json,{}">
and clicked the tag, works perfectly in both browsers.Basically, some browsers will ignore the download attribute if the document type is one that it can render natively.
I don’t think the content-type is the problem, instead the origin: because some ~paranoic~ people
a[download]
is ignored when the target is in other origin. Example: open this old project of mine in Firefox and click the download link (“can be downloaded”). Even if the downloaded file is a HTML file (which Firefox can render natively) it triggers the download. Note that Chrome is going to follow the same behavior as Firefox.Nice Article!
I found this post inspiring beyond buttons. Just good UX.
Buttons Do Things, Links Go Places
Put that on a poster.
What if your download UI element isn’t just for a single static asset, but is actually generating a custom file when you press it?
For example, if you have a list of files, you can check as many as you want, and pressing a download UI element zips those files together and then downloads that one file. In this case, we’d be using JS anyway, and the UI element is triggering more than just the link, it is ‘performing actions’, so a button would make sense, right?
But then if you also have regular static downloads that could be easily done as a link with a ‘download’ element. Would you still do these as links and the more complex one as a button, or would that inconsistency lead to issues? Especially if you wanted to style them similarly (because why wouldn’t you? For the user they are just downloading in both cases, they don’t need to understand the difference between static and dynamically generated files).
I think “buttons do things (configure the download), links go places (request the download)” still holds.
You’d still ultimately be requesting your custom download after fiddling with it, as you cannot alter a download’s contents on the fly (short of things like torrenting). It would also be pretty easy to alter the download attribute’s string based on button events.
I think you nailed it with the end user not needing to worry about the distinction between a dynamic or static download. Realistically, the aesthetics of the link is probably going to depend on existing design efforts. But this post is in part a plea to consider what you’re invoking visually and the expectations surrounding it.
One lesser-appreciated user-behaviour is when a user would like to choose an alternative download location.
On a download link, your user can right-click -> “save link as…” and place the download directly into a folder of their choice. Handy if you want something to go directly to removable media, for example.
On a download button, there’s no such option.
Worth noting: Chrome 65 will block the payload of links with the
download
attribute applied to them, if the payload is a cross-origin resource. I believe the attribute should still function as a selector, however.On my latest project, instead of writing both the verb and the noun as the text for the some of the download links, I wrote the verb ‘Download:’ as static text, followed by each noun (booklet, cover, video, etc.) as a vertically stacked button-y link (the old ghost link in a clear box with a full box-shaped border that matches the link color). I figure that even the least internet savvy person will understand that each box is meant to download the listed item and they will have a better idea of how long each type of file normally takes to download on their device.
The rest of the download ‘links’ are actually the download icon included with the native audio element, which also includes how long each track is in minutes and seconds, which I feel is another good non-specific indicator of how long each download will take.
Also, in the help page, I’ll explain how to find the files on their own device if they are savvy enough to follow a few basic instructions. After all, if they are using the extension I’m building, they have to have already downloaded it, MP3s, SVGs, MP4s, PDFs, and all.
Am I wrong to not include the word ‘Download’ in each link, to have styled the links like button-y ghost links, to use native download methods for music, and to not include a full write-up for each download? I’ve been trying to keep the UI and visible content minimal to avoid covering up the animated SVG background, but if ditching the music-video-like animation is necessary for adding a full explanation for users to understand what the downloads are, then I’ll just ditch them and set it up to look like a long listicle and ditch the help page.
The trouble with leaving the verb off is that if a user experiencing low or no vision is browsing with the aid of a screen reader, they may not be able to determine what the noun is for.
Screen readers can scrape the current page and create lists by content type (headings, links, buttons, etc.) for easer navigation. Static text that is placed in visual proximity to the download links will not come along for the ride if accessed via this method. While it might seem redundant to show the word “download” over and over again, including it can go a long way to providing context for users navigating without visual aids, or who have zoomed the page’s content to the point where the layout may not communicate the visual relationship.
If the page’s main purpose is for accessing downloads and its title and first level heading communicates this, I could potentially see a case for leaving the verb off. However, that will increase the ambiguity of purpose for the rest of the non-download links on the page. Screen readers treat browser extensions like little web pages, so I think the advice carries through.
I’m unsure of what extension you’re mentioning, but it sounds like track length is a great detail to include! I’d also recommend investigating the Reduced Motion media query for the animated background in order to accommodate for vestibular disorders, migraine triggers, etc.
Those are good points, though I wonder if alt text might work out better for screen readers without the redundant visual of a repeated verb. I don’t know if that will work, as it is an extension and not a website – the extension does not require internet access, except for the initial download.
To explain further what exactly I’m building, the animated background is a pure code equivalent to the old music video, but runs as long as the full length of the album, though without any event triggers to tie it to the music (the animation runs continuously for the full amount of time that the uninterrupted album lasts, but does not pause or jump to a different location in the animation). It’s also extremely slow animation, so it’s far more likely the animation may not be noticed for the first few minutes than it is to cause migraines or other motion-related triggers.
Also, most links on each page are downloads; the rest are for changing which track is currently playing (marked by brackets), volume, and play/pause (native to the audio element). There is no header, as clicking on the extension icon in the browser opens a menu (the only place where links open a new page), where the only choices are specific albums, a track from a compilation album, a single, a few samples for other music artists to use, an about page, and a short help page.
Due to the way extensions open in the browser, zooming is not possible, as everything is in pop-up form, not full-page. And while I do want the extension to be accessible to as many people as possible, I’d hate to ruin the visuals for everyone who navigate visually. Seeing as the main purpose of the extension is to provide music, I’m already leaving out anyone who is deaf or hearing-impaired.