Scriptaculous Draggable and Z-index

I was building a prototype today using the Scriptaculous Draggable object. It was a fairly simple idea, a set of 'items' along the top of the page which could be dragged onto a selection of timeslots below, the idea being that by dragging the item to the timeslot you are 'booking' the item for that timeslot. Obviously in the real application this would have to link back to a database and do all sorts of complex stuff, but for now I just wanted to mockup how the UI would work.

I started off aiming to get the basic functionality working and not worrying too much about design. The Scriptaculous stuff is easy to use, I set up my items and timeslots as div elements and gave them a class name, then in my initialisation function used getElementsByClassName to get an array of elements to which I could apply the behaviour:

var els = $('available').getElementsByClassName('cat');
for (var i=0; i<els.length; i++) {
    new Draggable(els[i],{revert: true});

The droppable bit was a bit more complicated as I added event handler functions for onHover and onDrop:

var els = $('times').getElementsByClassName('slot');
for (var i=0; i<els.length; i++) {
    Droppables.add(els[i],{accept: 'cat', onDrop: catchDrop, onHover: showCatch } );

My catchDrop handler inserts an item into the booking slot, or increments the number of that item if one or more is already booked, though initially I just popped up an alert to confirm everything worked as expected. The showCatch handler changes the background colour of the element when a draggable is moved over it. I tried using Effect.Highlight initially, but it didn't interact well with the drag and drop stuff - if you tried to add an item to the bottom booking slot, all of the slots above became highlighted as well. So I settled for changing the background colour and used a brute force approach of removing the background colour from all the other elements before applying to the current one. Here is what I'd got so far.

With the basic functionality working I set about styling the page with CSS. I envisaged a 'toolbar' of items across the top with an 'Outlook style' collection of timeslots below. Since, in the actual application, there could be any number of items, I made the toolbar a fixed height and width and set it to scroll along the x axis:

#available {
    width: 100%;
    height: 64px;
    overflow-x: scroll;
    overflow-y: hidden;

This had an unfortunate side effect, however. Now when I dragged my items down onto the booking slots they were hidden behind the slots, and this looked a bit stupid. I did some experimenting with z-index for the various elements involved, but didn't have much joy - I got it sort of working in IE but that 'solution' hid all the booking slots in Firefox, so I resorted to Google. The first thing I learned was that Scriptaculous sets the z-index of the draggable element to 1000 - so clearly that shouldn't be the problem. Next, I wondered if the float: left I'd applied to the draggable elements somehow interfered with the the z-index, which led me to an article, with an excellent example, on the Mozilla developer site. This was useful information, and clearly floating does have some effect but it looked like it wasn't what was causing my problem. Finally I came across a CSS-d wiki article on z-index stacking context. Although I'm sure I haven't fully understood the article yet, this seemed to be the problem - the draggable elements were now in a different stacking context to the droppable elements, and this is why my z-index experiments weren't working. This got me to the root of the problem - if it worked fine before any CSS was involved, then something in my CSS was messing with the stacking context. Commenting the rules out one by one soon revealed the culprit - overflow-x creates a new stacking context (or at least, has an equivalent effect) in Firefox, whereas it seems IE's broken z-index handling was what allowed me to end up with something which worked there.

Rather than delve even deeper into the mysteries of z-index I chickened out and did the page without the overflow, it's only a mockup after all (which is also why it's only been tested in Firefox and IE7, before anyone starts complaining &#58;&#41; )