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:
- Javascript deals with changing the size of the icons
- CSS describes the positioning
- 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
January 5th, 2006 at 1:11 pm
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
January 23rd, 2006 at 10:20 am
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.
February 27th, 2006 at 8:51 am
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 !!
May 3rd, 2006 at 7:50 pm
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.
November 3rd, 2006 at 4:28 pm
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.
November 8th, 2006 at 6:28 am
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
November 12th, 2006 at 8:27 pm
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?
November 12th, 2006 at 8:30 pm
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.
January 31st, 2007 at 1:25 pm
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.
February 7th, 2007 at 2:09 pm
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
February 7th, 2007 at 5:00 pm
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.
March 12th, 2007 at 10:08 pm
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
March 13th, 2007 at 3:38 pm
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.
April 15th, 2007 at 9:06 pm
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!