Before I even begin I want to state that this shouldn’t be used as a definitive source for this information. I am utilizing an older version of Firefox (3.0) and IE7 for all my tests. I can’t vouch for Chrome, Opera or Safari’s take on any of this, but I gather that it is much the same.
At some point in your web programming or web design career you will inevitably encounter the dreaded file upload “utility”. This piece of crap, is only present to allow users to select a file on their machine and eventually transfer it to your servers. Of course, this is a vital piece now, but perhaps at the time it was something that was easily overlooked. After all, at a time when your ISP speeds were approaching the 14.4kbps mark, uploading files was really something only the computer geeks did.
Now however, with profile pictures, online resumes, cloud storage and so much more, the file upload feature is front and center. Some places have gone so far as to eliminate the default HTML object and instead go with a Flash equivalent. This doesn’t really fix the issue, it’s like me saying “oh your computer doesn’t work? Here, use my iPad” 1 It’s just a bypass. We need to fix this now! It’s already too late, we’re just playing catch up.
Understanding the Process
File uploading is one of those features that, if you’re unlucky, you’ll have to design a layout around. That’s because, for some reason, every browser has decided that the File upload object is completely immune to CSS. No amount of styling can ever achieve what you want. It will always look like ass.
There is no easy way to style it, there is no way to replace it (unless you use flash, but that’s a whole different issue) and the only way to get around it is to hide it or integrate it directly into your design. There is absolutely no way to pretty it up. You can’t adjust the size of the button or the size of the input box. You are essentially stuck, with what you see. No way around it. Or is there?
Short of changing your entire design to work with default form elements (euych!) the only way to fix the file upload feature is to hide it completely. See, because we can still apply some style features to an encapsulating element 2. So we could technically just hide the entire form field, and absolutely position it over our custom designed field. If we do it all right (we WILL have to use either a custom IE stylesheet or a bunch of hacks) we can make it look like our pretty file upload field is actually doing the work!
The Code
The code for this is primarily CSS with some JavaScript sprinkled in to make sure that everything is positioned where it should be. I am utilizing the jQuery library for a lot of this simply because I use it in a lot of my projects. If you use any other libraries, they should all have equivalent methods and if they don’t, you should ditch them and switch to something else. If you are trying to follow along in straight JavaScript good luck. One of the primary reasons I work with a JavaScript library is because of cross browser inconsistencies. With a library, I can be sure that someone has gone through the painstaking task of setting up different kinds of math and implementation for the different browsers.
<html> <head> <title>File Upload</title> <style type="text/css"> </style> </head> <body> <div id="fake-file"> <input type="text" id="fake-file-title" name="fake_file_title" value=""> <button>Browse</button> </div> <div id="file-constraint"> <input type="file" id="real-file"> </div> </body> </html>
The CSS below is what we will be using to style our new input fields.
#fake-file input { -moz-border-radius: 3px; border: 1px solid #555; -webkit-border-radius: 3px; -o-border-radius: 3px; -khtml-border-radius: 3px; border-radius: 3px; padding: 2px; } #fake-file button { -moz-border-radius: 3px; border: 1px solid #555; -webkit-border-radius: 3px; -o-border-radius: 3px; -khtml-border-radius: 3px; border-radius: 3px; padding: 1px 8px; background-color: #FFF; }
Now it’s as simple as adding some positioning values to our file-constraint field. We will also alter the z-index and position it higher vertically than our fake file upload. Then we can simply utilize some JavaScript to make things work like it should.
#file-constraint { position: absolute; top: 0px; left: 0px; z-index: 2; display: none; }
Bam instant hidden. Based on the position of your actual fake file field the top/left attributes will obviously change. The JavaScript is just as simple. I am utilizing jQuery to hook in to the onChange event for the real-file field, but it’s not necessary. You can do the same without a library. I just prefer jQuery because it means I can target all browsers the exact same way.
$('#real-file').change(function(e) {
var str = $(this).val();
str = str.split('\\')[str.length-1];
$('#fake-file-title').val(str);
});Basically we get the value of the file upload field. In Firefox this is just the name of the file, while in IE it contains the complete path to the file. I prefer stripping out the path, but that is up to you. Basically the value from the real file field is just assigned to the fake file field.
Working with file uploads are a hassle and this really only covers a portion of the client-side. There are still many things to take into account such as temporary file locations, file permissions, fake-ajax / standard uploading etc. This tutorial isn’t meant to be a complete compendium of all things file uploading, but merely to point out some annoying UI inconsistencies.
Notes:
- I really don’t have one http://wheremy.feethavebeen.com/2010/02/blagging-about-the-ipad/ ↩
- A div that contains the file upload field, for example ↩
