Posted on 3rd April 2009 —Gareth Edward asked how to achieve the effect on the latest BBC Radio 1 website, where the mouse rolls over the image block, tabs slide up and the image zooms a little to reveal more of the picture.

Watch

BBC Radio 1 effect

The first thing I noticed about the effect is that it’s done in Flash. I’m a big believer in knowing where Flash has it’s place: the high end of the effects within browsers (amongst other places).

Equally though, I can how this effect can be achieved using JavaScript and it not taking too much toll on the browser.

There’s three things that are happening in this effect:

When you roll over the image, it zooms out slightly to reveal more of the image. Notice that it also keeps the top position static.

The navigation slides in to view from the bottom of the box, and mousing over the link will trigger showing a different image.

The images automatically change with a swipe effect.

I’m going to set aside the 3rd effect for now (perhaps I’ll do a screencast on it in the future) and focus on the first two.

Deconstructing the effects

The first thing I want to aim for is that the layout works without CSS, and the technique works without JavaScript enabled.

Roll over zoom

The only way we can get an image to appear to zoom is by having the actual image element and increasing the height and width. However, I’m going to create these image elements on the fly because when my page runs without JavaScript I want the images to appear in the background of the panels.

I’m still in two minds as to whether this should be a background image. The image certainly doesn’t add any value from a content point of view, so without CSS I think it looks right, but I’d be open to hear your opinions.

When these images are created they need to have their size increased by a defined percentage (which we’ll make a parameter), so that when we roll over, the image is resized down to it’s original size, giving the impression of a zoom out.

Given that we are going to stretch these images across the total height and width of the panel, it also means we need to wrap the content that’s initially in the panel in an element with a higher z-index to make sure the actual content can still be seen and used.

Navigation slide up

We need our navigation bar to reveal upwards. To achieve this we just need to position the navigation absolutely (which also helps our non-JavaScript version of the page), and use the animate method to animate the height from zero to the real height of the navigation item – which we’ll capture during initialisation.

HTML & CSS

The HTML for the solution is a pretty simple tab system, with the only slight exception that our tab panels are wrapped in a div:

As for the CSS, as an experiment, I’ve used EMs throughout the CSS – there’s no reason why you can’t use PXs. I was just interested in seeing the example being zoomed by the browser. I’ve set the body font-size to 62.5% so that 1em is equal to 10px.

The only slight deviation away from a traditional tab set up is the navigation is set at the bottom, and because I know with JavaScript we’re going to use absolutely positioned image elements, the ul.tabs has the following CSS position absolute and a z-index:

.tabs {
position: absolute;
bottom: 0;
z-index: 1;
}

Aside: Tabs without JavaScript

If you open look at the solution now, with JavaScript disabled, you’ll see that because we’ve wrapped our tab panels in a div with overflow: hidden, we’ve now created a tabbing system that works entirely without JavaScript.

If you wanted to use this in production: you need to be wary of ensuring the height of the panels is equal (since it is just overflowing) – otherwise this is a fairly clean way to tab content without the need for JavaScript

jQuery

Convert background images to foreground images and apply styling to give them a default state of zoomed in

Zoom the image inwards using an animation

Slide the navigation up and down out of view

Hovering over the navigation will change the tabs

I’m going to give you each part separately, then you can see the whole thing put together in the completed example.

Converting background images

As I’m trying to make a plugin, I’m saying that I don’t know anything about the images or height or width of the panels.

We need to loop through each panel, take the background image and create a new image with that url. Once that new image is loaded, we’ll pull out the height and width, work out the zoomed in height and width (which will be a percentage larger than the initial size), strip the panel of it’s background image and then insert the new image in to the panel. Phew! That’s sounds like a lot!

The panelIds variable contains a string such as: #one,#two,#three – since this is the hash on the href the tab links, which we immediately capture as a jQuery instance.

Next, we loop through the $panels to convert the background images to foreground images.

bg = $panel.css('backgroundImage').match(/urls*(["']*(.*?)["']*)/),

This is a regular expression that captures the background image. It’s written to try to handle different cases in that the url could be plain, wrapped in single quotes or it could be wrapped in double quotes.

We test if we did successfully find the background image (which you may argue we don’t need since this plugin has a very specific purpose), and if it was found, we’ll create a new image.

Before we hook in to the image load event, we do two things: 1) remove the background image, and 2) wrap the panels contents in a div:

Zoom the image

I’ve created a separate function to handle the zooming in and out of the image. This is because it will be called from two different places with only one single different – which variable to use to set the CSS – either ‘fullView’ or ‘zoomView’ which we set just above.

In this function we loop through the images that we captured in the images array. From there we say if the image is visible (i.e. it’s the currently active panel), then animate it’s CSS properties (either zooming out or in – this is defined by the zoomType).

If the image isn’t visible, we need to just change the CSS properties without the animation. This is because when the user switches to a different tab, the image must be in the same zoomed state as all the other panels.

Slide the navigation up and down

Next we need to say, if the user hovers over the whole thing, we want to:

The hover over is fairly simple, we stop the effect from running on the $tabs to prevent it from jumping and down madly, and we animate the height to a pre-captured height (which would happen in the initialisation phase).

Hover off is slightly different. We do the same, animating down to zero, but then we use a callback function to hide the navigation, this is to ensure it’s completely hidden once the effect has finished (because in my example, I’m using a border, and animating the height to zero would leave the border visible).

Hovering over navigation

Finally, since I’m replicating the effect on the BBC (certainly 2/3rds of it), I want to hover over the tabs to trigger the panel to switch. However, I don’t want it to trigger straight away, say if I accidently hover over a tab – so I’m using a bit of simple hover intent (you could well use the full plugin to achieve this though):