Over two years ago I wrote an article about using the device camera on the web without using PhoneGap (Capturing camera/picture data without PhoneGap). While an old blog entry, it is easily one of the most popular entries on this blog in terms of how much traffic it gets. It is also a great reminder that most of us web developers probably forget just how powerful the platform is. The original article discusses the use of the capture attribute in input fields to allow for camera access. The idea was simple - take a regular input/type=file and add the capture attribute:
<input type="file" capture="camera" accept="image/*" id="takePictureField">
When used, the browser would then prompt you to select a picture or take a new one with your camera. You can see the original demo below, and my god, iOS has really come a long way since then.
I thought it would be interesting to take a look at this feature and see if it has changed any in the past two years.
I began by checking into the official spec. This proved a bit difficult. While there is a spec for Media Capture and Streams, I was more interested in the particulars of the syntax in regards to the
I went to MozDevNet’s input page and it had this to say about the capture attribute:
When the value of the type attribute is file, the presence of this Boolean attribute indicates that capture of media directly from the device's environment using a media capture mechanism is preferred.
Note - “this Boolean”. When I last worked with this code it wasn’t a boolean but rather a value specifying camera.
To make things even more interesting, this older article from 2013, Capturing Audio & Video in HTML5 used the accept attribute instead:
<input type="file" accept="image/*;capture=camera">
Back on the MDN page, if you look at the
accept attribute, nothing about this is mentioned. However, their docs on capture link to a spec that mentions:
If the accept attribute's value is set to a MIME type that has no *associated capture control type*, the user agent must act as if there was no capture attribute.
Notice the “associated capture control type”? So that seems to imply that - officially - you should use
capture="true" along with the
accept attribute which may or may not specify a particular capture type or may stay nice and vague, i.e.
Clear as mud, right? Ok, so let’s play with this a bit. I built a demo that tried to hit a few variations of this:
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width"> <title>Capture Tests</title> </head> <body> <h1>test 1 (capture attr)</h1> <input type="file" capture="camera" accept="image/*"> <h1>test 2 (capture in acc)</h1> <input type="file" accept="image/*;capture=camera"> <h1>test 3 (capture bool)</h1> <input type="file" accept="image/*" capture> <h1>test 4 (capture bool, video)</h1> <input type="file" accept="video/*" capture> </body> </html>
You can see four different input fields. The first uses the capture attribute, while the second uses it as part of the accept attribute and the final two use them both, as I believe the spec dictates. Also note the last is asking for video. So let’s see what happens.
The first and second buttons behave the same way. Consider the screen shot below.
Notice the “Take Photo” and “Photo Library” options allowing for both a new and old picture. Notice Dropbox. I only see that because I clicked More:
I was a bit surprised that Google Photos didn’t show up here, but maybe they need to do something to let iOS know they are a “provider” for images.
While iOS prompted for a picture, I was able to go into the photo library and select a video. I was also able to go into Dropbox and select a file that wasn’t media at all. This is not a bug and I would hope that if you are building an app that accepts any type of upload that you always verify on the server that the right type was sent!
Here’s where things get interesting. My third test, which asks for an image but doesn’t specify camera anywhere, had this result:
As you can see, now it’s asking for either a picture or video. Finally, the fourth option - and it’s what you expect - prompting for a video:
Mobile Chrome does things a bit differently. The first input opens up the device camera. The second prompts you for an ‘action’:
Camera and Camcorder act as you expect. Documents let me browse my tablet, and notice Dropbox shows up here too.
And just like iOS, I can go into Dropbox and select something that isn’t an image or video.
Input #3 acts just like Input #1 - it opens the camera. I honestly can’t tell you why.
Finally, input #4 also opens up the device camera, but sets it in video mode automatically.
So for the heck of it, I decided to try a few desktop browers as well. Here is what I saw.
Like Mobile Chrome (and it shouldn’t be surprising), input #1 and #3 act the same. The open a file selection prompt that defaults to Images:
And notice how you can simply change Format and select non-image files. Input #2 acted as if I didn’t want an image:
Finally, option 4 prompted for video files:
Firefox acted the exact same way as Chrome. Inputs #1 and #3 selected a format of Image Files, #2 wasn’t filtered at all, and #4 set a format of “Video Files”.
So at this point - I tried a fifth test. You won’t see it in the earlier screen shots, but here it is:
>input type="file" accept="image/*;capture=camera" capture<
This “felt” like it should match the spec best, but both Firefox and Chrome treated it like no particular filter was active. Mobile Chrome prompted for Camera/Camcorder again. Mobile Safari did the prompt thing again, but asked for either a photo or video.
Safari acted a bit like Chrome/Firefox, but the UI doesn’t tell you it’s filtering. Instead, it grays out the non-desired options. Like Chrome/Firefox, inputs #1 and #3 acted the same:
As you can see, only images are available and as an end user, I can’t change the option at all. (But of course, don’t sit there thinking to yourself that this means you’re “protected” from non-image uploads. I can go into Safari’s dev tools and modify the code.)
Input #4 acted the same - only my videos were selectable. Finally, the new fifth option acted like Chrome/Firefox - no filters were in place.
Microsoft Edge doesn’t seem to recognize any of the options. Of course, it “breaks” perfectly well and still lets me select a file to upload, and since I’d have server-side protections in place, I’m certainly not “broken” in Edge at all.
So on mobile, it looks like this feature still works rather well, with the biggest difference being that Mobile Chrome lets you go right into the camera whereas Mobile Safari is always going to prompt. Safari’s prompts seem easy enough so I don’t see this as an issue, but obviously user testing would let you know.
If you want to use my test page yourself, you can find it on Surge at: http://regular-rod.surge.sh