Making Images First-Class Citizens of HTML Forms – Part 1

Despite the fact that this is 2011, despite the fact that web applications have been the Next Great Thing for, well, nearly 7 years, User Interface design on web sites still has a long way to go to match native applications. While this is expected to change, as great efforts are underway (with even Microsoft making web applications first-class citizens of their upcoming Windows 8, wow), we still need to cater to users which do no use the latest, greatest web browser, and hack the site to support the largest userbase possible.

One problem many web developers are likely to have stumbled upon is file uploading, especially when said files are parts of a larger document the user is trying to compose using a web application (This especially applies to images, but this also could apply to any kind of media which has to be uploaded, like sound or video). And even in cases where “document” and “composing” seem to be very big words (say, a simple “user profile” form where the user can upload an avatar picture), the standard, classical HTML way of doing things feels a step backwards from what native user interfaces have provided for ages.

Let’s say, for example, I want to include a picture in a document I am composing in a word processor:

  1. Just drag & drop the picture file in the place where you want it to appear

Or, alternatively:

  1. Position the cursor where you want the picture to appear
  2. Click on “image”
  3. Browse local files to find the image, and confirm.

In both cases, the image is visible on the document before I have to submit / save the document. The same would apply for, say, changing my profiles’s avatar on Skype.

Now, let’s say I want to include a picture in a document I’m editing in a Mediawiki site, or on a Trac site, or any site using the classic way of importing files:

  1. Start to compose the document, then click “Import File” to add an image to this document
  2. “Import file” is a new page, therefore the text I already entered may be lost when I follow this link. Mediawiki, for example, will ask me whether I really want to quit the page (and lose all my work), or continue to the file importation page.
  3. Cancel, and open the “import file” in a new tab
  4. Click on “Choose a File” on the new page
  5. Browse local files to find the image, and confirm (alternatively, drag-and-drop the file in the “Choose a File” form element)
  6. Click on the “Import File” button
  7. Remember (or copy) the name of the file which was uploaded
  8. Return to the original document composition page
  9. Type (or paste) the file name on the document I am still composing, using the appropriate syntax to include an uploaded file.

Is this really sane? Isn’t there, really, from an user-experience perspective, a better way of doing this?

Well, we’ve gotta love rhetorical questions, but of course there is a better way of doing this. Even on a web site. Let’s say, for example, you want to compose a Google Plus post, and, while composing it, decide you want to attach an image:

  1. Start composing the post.
  2. Drag and Drop the image to the post you were composing.

And… That’s all. A preview of the image you want to include appears under the post you are just composing, so you can preview it, or delete it, before submitting. You submit your post normally, and the image you just drag & dropped is included within. No questions asked, works as expected.

Works as expected to people used to deal with desktop applications, anyways. To web developers, it may seem it works like magic. Dark magic.

In my humble quest of developing user-friendly, efficient web applications, I’ve gathered several techniques allowing to achieve similar magic. Those will be detailed in subsequent posts.

Faux Absolute Positioning, Revisited

The problem

We have a container, inside which there are elements.

  • We want elements to be positioned in an absolute-like fashion, or be horizontally centered, with a fixed “top” value.
  • We want the elements to appear on top of one another.
  • We want the container to expand so that it contains all elements.
  • We want it to be compatible with most major browsers, IE6 included.

If, let’s say, we have the following markup:

<div class="container">
    <div class="child">
        <p id="item1">Blah blah blah</p>
    </div>
    <div class="child">
        <p id="item2">Blah blah blah</p>
    </div>
</div>

We would like it to be rendered this way:

Positioning 1Or even, that way:

Positioning 2We do not know, in advance, the sizes of item 1 and item 2, but we still want the container to grow to accomodate them.

I have seen several solutions to such a problem, many using Javascript to clear absolutely-positioned elements, but we are looking for a pure CSS solution here. There is also “faux absolute positioning“, which is much more interesting, but still does not quite solve the problem.

The solution

Let’s build on the faux absolute column solution:

.container {
    border: 1px solid black;
    overflow: hidden; /* To clear contents */
    zoom: 1; /* To fix IE6 bugs with floats */
}
 
.child {
    float: left;
    margin-left: -100%;
    position: relative;
    left: 100%;
    width: 100%;
    text-align: center;
}

What happens here?

  • All children are floated to the left. However, due to the use of a 100% negative margins, there is always space to float a new child at the relative position (0, 0)
  • The children’s content is replaced, using relative positioning, inside the container.

Now, let’s position contents, for the first case:

#item1 {
    display: inline-block;
    width: 300px;
    height: 100px;
}
 
#item2 {
    display: inline-block;
    width : 200px;
    height: 200px;
}

Or, for the second case:

#item1 {
    display: inline-block;
    width: 300px;
    height: 100px;
}
 
#item2 {
    margin-left: 20px;
    margin-top: 70px;
    width : 100px;
    height: 100px;
}

Result

For the first case:

Blah blah blah

Blah blah blah

For the second case:

Blah blah blah

Blah blah blah

Drawbacks

This technique works with most major browsers, including IE6 using the “zoom:1″ hack. Otherwise, no CSS hacks are employed (negative margins are a standard feature which works as specified).

Of course, this solution is not perfect. The main drawback is that it requires each element to be contained in an extra <div>, called here “child”.

This is the Start of an Adventure

Erm. Hello? Anybody in there? Looks like this place is new.

This is a brand new blog, still smelling of fresh pixels, and waiting for be themed and loved and filled with interesting and insightful content. A brand new blog for a new turn, for the start of a new adventure, who knows where it will lead? For this is the beginning of this blog, the dawn of a new project, the genesis of Midsummer Web Development.

Improbable visitor from the interwebs, or robot crawling around this place, I salute you!