nickjarman.com

Mac OS X-style Dock in Javascript

7th May 2005

See a demo: Dock Demo (opens in a separate window)

See it use: This example at www.fr-j.com shows how good it looks with a set of nice icons.

A few weeks ago, I read an article on The Register about an implementation of a Mac OS X style Dock in Javascript. It was written by a developer at Google, and appeared very briefly in Google Labs. Unfortunately it appears to have been swiftly removed from the site by mutual agreement, so I didn’t have the opportunity to see it in action.

I thought this was a shame, as it’s an interesting use of Javascript. I also started wondering how hard it would be to implement, so I thought I’d have a go at it myself. The result is at the top of this page - just run your mouse pointer over the icons to see the effect.

This is not intended to be an exact copy of the Dock’s behaviour, but it feels quite similar to use. It’s a while since I’ve used Mac OS X, so any inaccuracies in the following text are due to poor memory! The main difference between my Javascript version and Mac OS X’s is how the icons in the Dock grow in relation to the position of the mouse pointer. A Mac OS X Dock icon reaches its maximum size when the mouse pointer is over it. Icons to its left and right are also enlarged, to create a wave-like ripple which peaks smoothly at the active icon and blends smoothly back into the row of inactive icons.

My implementation simply enlarges the icon as soon as the pointer moves over it, using the onMouseOver event, and shrinks it back to its original size when the pointer leaves it (with the onMouseOut event). It’s quite simple in isolation, but when you run the mouse pointer across a row of such icons, the effect is superficially similar. The wave-like effect isn’t as elegant as Mac OS X’s, and is lost entirely if you stop moving the mouse. However, it probably looks similar enough to fool most people into thinking it’s the same thing. It also has the advantage that there’s no need to determine the pointer’s position on the screen - which involves browser-specific Javascript.

Another minor difference is that the images in my Dock expand downwards instead of upwards - probably more useful if the navigation appears at the top of the page. It’s possible to have the icons expanding upwards, but it would be slightly messier because a transparent image or the maximum height would have to be added to the dock to force the baseline on which the icons are aligned to be a constant distance from its top margin.

So, how’s it implemented?

There are three main components:

  1. Javascript deals with changing the size of the icons
  2. CSS describes the positioning
  3. XHTML glues it together

The Javascript

The code is scattered with numerous comments, so requires little explanation. In short, there are two entry points, enlarge and reduce, which must be called on the onMouseOver and onMouseOut events for each image in your Dock. Both these methods take a single parameter - the DOM element itself, obtained using this. See the XHTML below for an example.

The shrinking and growing is done in steps, in order to achieve smooth animation. This is done using a timeout, which causes a nominated function (in this case doResize) to be called after a set interval.

Download the Javascript: dockdemo.js

The CSS

Since this might be used for navigation, and the current fashion is to implement navigation areas as an unordered list, that’s precisely what I’ve used as a container for the Dock. I suppose you could use any block-level element you like.

The text alignment of the <ul> element is set to be centred, and the <li> items it contains are set to display inline. This causes each <li> to be treated the same way as a single character. The effect of these two simple CSS rules is that the icons in the Dock are always centred, regardless of their sizes, giving a very similar appearance to Mac OS X.

Download the CSS: dockdemo.css

The XHTML

This simply consists of an unordered list with the approriate ID. Each list item contains a single image, for which the onMouseOver event calls enlarge(this), and onMouseOut calls reduce(this).

The odd formatting of the </li> tag (note how it is closed on the following line) is necessary to prevent whitespace appearing between each icon. If the </li>; tag were closed on one line, and the following <li> tag placed at the beginning of the next, the line break would be interpreted as a single space character.

Unfortunately this appears to be standard browser behaviour, as defined by W3C - I find this strange: no elements other than <li> are permitted within a <ul>, so surely it makes no sense to display any whitespace between them! At least if you can look past the slightly messy markup, the underlying structure is quite simple and elegant.

Download the sample XHTML (be sure to right-click on this one) dock.html

14 Responses to “Mac OS X-style Dock in Javascript”

  1. Janice Says:

    Wow, exactly what i was looking for !!! Thank you very much for sources and inspiration. Your idea is part of my website now. Any Wishes? Yes, i would like to use scalable svg icons - but your script only works with IMG Tags. Maybe this would be an hint for the furure :)

  2. Nick Says:

    I’m glad you found it useful, it looks excellent on your site, so I’ve added a link to it at the top of the article. SVG icons would certainly be an improvement, to make the scaling smoother - I might look into that later.

  3. Janice Says:

    Hi Nick … Thank you -> but just used what you gave me :) … Well, SVG?!?! I tried with your script - but until now: No, not such a good idea i thought! The svg support from firefox to safary is still to “bad”. So, in this way i’ll try another way: Scale a small image to the final size and after that overlay an 100% clean version of the image. Another problem: Even the new IE7.0 still seems to have problems with the png’s alpha-channel :( So, still lots to do !!

  4. noel Says:

    Hi Nick - thanks for this. I’ve implemented it for a client of ours, and they’re quite pleased with it! I modified it slightly to expand up instead of down, and have added some rollover actions.

  5. Kyle Bellamy Says:

    I’m playing around with this and seem to be haveing a very strange thing happening. I did not change anything except for the images but they seem to be resizing only horizontally.

    Any idea why this might be? Same thing in both IE7 and Firefox2.

  6. Steve Says:

    Hi there,
    Just read your informative article on the dock-like rollover effect. It looks really good and I would like to try it for my site. A question: do you think it will work on older browsers? I want my site to be accessible to as many people as possible.

    Thanks

    Steve

  7. Nick Says:

    Kyle - I just tried it out with IE7 and the images resize correctly (they are all JPEGs). What format are the images you are using?

  8. Nick Says:

    Steve - I’ve only tested it with IE6, 7 and Firefox, which covers the vast majority of browsers in use. In theory it should work with any browser with supports XHTML, CSS and Javascript, but they all have their own quirks.

    If there’s a specific ‘old’ browser that you know a significant number of visitors to your site use, it would be a good idea to test with that, so you can be absolutely sure what they are seeing.

  9. rodrotten Says:

    just a heads up if you haven’t already fixed it…if you have a height specified in the tag, the image will only expand horizontally. no big deal, but i wanted to shrink the original image so the expanded one didn’t look so grainy. very cool regardless. thanks buddy.

  10. Ryan Says:

    Hi,

    Love your script and am using it in my site (if that’s OK ;) )

    One thing…if the thumbnails are say 800px in width and the area is 900px, when the image expands, the thumbnail then drops underneath and creates a mess.

    Is there a way of having the overhanging images just hide until they arre visible again?

    Hope you can help me.
    Ryan

  11. Nick Says:

    Ryan - good question. You can solve this by changing the styling of the dock list. Just add…

    white-space: nowrap;

    …and any images which do not fit into the dock will be clipped. The only problem is that clipping occurs on the right-hand side, but it’s better than having the images wrapping like they did before.

    I’ve updated the example on the site, so you can try it out, and also download the new CSS file with the fix in it.

  12. Brent Says:

    I love the script, but I was wondering if I position it on the right side of the screen and have it running verical instead of horizontal. “float:right;” How can I make it grow out from the left and not from the right

  13. Nick Says:

    Yes, you can do this quite easliy. All you have to do is modify a few items in the stylesheet. For the dock container (ul#dock), replace:

    text-align: center;
    height: 130px;

    with:

    text-align: left;
    width: 130px;

    This will fix the width instead of the height, and position the images so that they grow from the left-hand edge. Now we need to position the dock container on the right-hand edge of the page: add the following…

    float: right;

    Finally, change the list items (ul#dock li) so that they are not displayed inline. This will ensure that they are stacked one on top ot the other. Do this by removing the following:

    display: inline;

    That’s all! I’ve put an example here:

    http://www.nickjarman.com/dock/verticaldock.html.

  14. Allen Says:

    Nick: great job on this. I’m using your script on my photography site. If you don’t mind helping on this, I have two how-to questions:

    1. I would also like to have image rollover swaps (for the enlarged icons). I’m not sure how I’m able to incorporate that to your dock.js

    2. Is there anyway to put a on/off button to toggle the magnification effect (without reloading the page again)

    Many thanks!