Horizontal Accordion Slider with Vertical Text

In this tutorial, we’re going to take a look at how to build a horizontal accordion slider using CSS 2D transforms and a bit of jQuery.

Typically, the trickiest part about this kind of horizontal accordion is getting the text on the accordion “spines” to display vertically, so people usually use images to display the text. It’s not simple, but using some CSS 2D transforms, we can actually make the text display vertically without using images.

2D transforms work in most modern browsers, but for those that don’t, we’re going to have our accordion degrade gracefully, without resorting to images.

Caveat: This isn’t a WordPress tutorial… yet. Wait for it, one step at a time!

View a demo
Download the PSD

Step 1: Photoshop

So let’s take a look at our design. It’s not going to win any awards, but it’s clean and straight forward. There are a few challenges related to there being borders between each spine, but we’ll address those with the CSS. For now, let’s just slice out the images.

Shark-week inspired

Shark-week inspired

Slicing The Image

When we slice out the spines, we’re going to take the borders on each side. The easiest way to do this is to just slice out one of the spines, and then save it for the web 4 times, changing the number each time.

You only have to make one slice, then re-save it 4 times.

You only have to make one slice, then re-save it 4 times.

If you’re following along with my PSD, the images are pre-sliced. We’ll also need the background and the main images.

A CSS sprite would be more efficient, but I’m trying to keep things simple.

While we’re going through the HTML and CSS, I’m actually not going to use the images at first, I’m just going to use regular CSS backgrounds, to keep things simple.

Step 2: HTML

The markup for our accordion is pretty simple. The whole thing is one unordered list, where each list item is a slide. Inside each list item, we have an anchor tag, which will be the trigger for the slide, and the slide content. Give the first slide a class of “active” so that we can style it differently if we like.

<div id="accordion">
	<ul id="slides">

		<li class="slide open active" id="slide-1">
			<a class="slidebutton" href="javascript:void(0);">Jellyfishes of the Deep</a>
			<div class="slide-content">
				<img src="images/image1.jpg" alt="image1" width="590" height="290" />
			</div><!-- slide content -->
		</li><!-- slide 1 -->

		<li class="slide open" id="slide-2">
			<a class="slidebutton" href="javascript:void(0);">Shark Week</a>
			<div class="slide-content">
				<img src="images/image2.jpg" alt="image2" width="590" height="290" />
			</div><!-- slide content -->
		</li><!-- slide 2 -->

		<li class="slide open" id="slide-3">
		 	<a class="slidebutton" href="javascript:void(0);">Swimming with the Fishes</a>
			<div class="slide-content">
				<img src="images/image3.jpg" alt="image3" width="590" height="290" />
			</div><!-- slide content -->
		</li><!-- slide 3 -->

		<li class="slide open" id="slide-4">
			<a class="slidebutton" href="javascript:void(0);">Dolphins & Friends</a>
			<div class="slide-content">
				<img src="images/image4.jpg" alt="image4" width="590" height="290" />
			</div><!-- slide content -->
		</li><!-- slide 4 -->

	</ul>
</div><!-- accordion -->

Step 3: CSS

First, we’re just going to do a basic reset and get some of the structure set. The only really important thing here is the width of the list items: it should be the width of a slide, including the trigger, but not including the leftmost border.

The slide content width is just the width of the content images. The 50px margin refers to the width of each trigger.

html, body, div, span, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, code,
del, dfn, em, img, q, dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, dialog, figure, footer, header,
hgroup, nav, section {
  margin: 0;
  padding: 0;
  border: 0;
  font-weight: inherit;
  font-style: inherit;
  font-size: 100%;
  font-family: inherit;
  vertical-align: baseline;
}

#accordion {
	position: relative;
	width: 795px;
	height: 290px;
	margin: 60px auto;
}

#slides {
	list-style: none;
	width: 795px;
	overflow: hidden;
	height:290px
}

#slides li.slide {
	overflow: hidden;
	clear: both;
	width: 640px;
	background: #00202f;
	height: 290px;
}

#slides .slide-content {
	width: 590px;
	height: 290px;
	color: #444;
	margin-left: 50px;
	padding: 5px 0;
}

Right now we just have a semi-styled list of images with room for our trigger spines.

It doesn't look like much yet

It doesn't look like much yet

Next we need to get all those slides to pile on top of eachother, instead of coming one after the other. To do this, we’re going to use some clever absolute positioning and z-index values. Well, not that clever. But handy. The left values for each slide are just multiples of the 50px triggers.

#slide-1 { position: absolute; top: 0; left: 150px; z-index: 4; }

#slide-2 { position: absolute; top: 0; left: 100px; z-index: 3; }

#slide-3 { position: absolute; top: 0; left: 50px; z-index: 2; }

#slide-4 { position: absolute; top: 0; left: 0px; z-index: 1;}
We have a 4-slide pile-up. Ha-ha...ha.

We have a 4-slide pile-up. Ha-ha...ha.

Now comes the tricky part: styling the triggers with vertical text. Let’s take a look at the code then go over the tricky bits:

#slides a.slidebutton {
	display: block;
	-webkit-transform: rotate(270deg);
	-moz-transform: rotate(270deg);
	-webkit-transform-origin: 120px 120px;
	-moz-transform-origin: 130px 130px;
	width: 300px;
	height: 50px;
	position: absolute;
	top: 70px;
	text-align: right;
}

Okay, so after we set the display to block (because anchors are inline), we’re rotating the text around 270 degrees (3/4 of a rotation). Because we’ve rotated the element, height is now width and width is now height, so we set the height to 50 and the width to 300. Similarly, the padding-top actually refers to padding to the left padding on the text.

All our slides in a row

All our slides in a row

I’m going to admit, I’m not really sure how the transform-origin property works, all I know is that I tried adding it on a whim, it turned out to be the secret ingredient that makes this all work. I messed around with the values for a while until I found one that worked.

If you’re using different sized elements than me, you’re going to have to adjust both the -transform-origin values and the top value. I suggest using [Firebug for Firefox] or just the webkit Inspector to view your changes real-time in the browser.

Anyways, so now we’ve got what’s starting to look like an accordion slider. Time to animate this puppy!

Step 4: jQuery

Now, I can’t take credit for the javascript in this tutorial, I found it and modified it from [this website] ages ago when I was building an old version of my portfolio.

$(document).ready(function() {

    $('.slide')
        .bind('open', function(){
            if(! $(this).hasClass('open')){
                $(this).next().trigger('open');
                $(this).addClass('open');
                $(this).animate({left: "-=590px"});
            }
            else{
                $(this).prev().trigger('close');
            }
            $(this).siblings().removeClass('active');
            $(this).addClass('active');
        })
        .bind('close', function(){
            if($(this).hasClass('open')){
                $(this).removeClass('open');
                $(this).animate({left: "+=590px"});
                $(this).prev().trigger('close');
            }
        });

    $('.slidebutton')
        .click(function(){
            $(this).parent().trigger('open');
            $('#content-' + $(this).parent().attr('id')).trigger('show');
        });

});

You can more or less copy and paste this code into your own project, the only value that needs to be adjusted is the animation, which should be equal to the width of your slide content.

Step 5: Make it pretty

Now that we have our ugly, but functional, slider working, let’s add in those images from before to make it pretty.

We’re going to add in the spine background images to each slide. Make sure to remove the background colour from the list elements.

#slide-1 {
	position: absolute;
	top: 0;
	left: 150px;
	z-index: 4;
	background: url(images/spine1.jpg) no-repeat left;
}

Next we add a bit more styling to the text:

#slides a.slidebutton {
	display: block;
	width: 290px;
	height: 55px;
	position: absolute;
	-webkit-transform: rotate(270deg);
	-moz-transform: rotate(270deg);
	-webkit-transform-origin: 120px 120px;
	-moz-transform-origin: 130px 130px;
	top: 70px;
	padding-top: 15px;
	text-align: right;
	color: #fff;
	text-decoration: none;
	font-family: Helvetica, Arial, sans-serif;
	font-size: 18px;
	text-shadow: 1px 2px #077691;
}
Lookin good!

Lookin good!

And finally add in the background:

body {background: #012d42;}

#accordion {
	position: relative;
	width: 795px;
	height: 290px;
	margin: 60px auto;
	background: url(images/bg.jpg) no-repeat;
	padding: 5px 0;
}

The finished product
Download the PSD

And there we have it, a fully functional horizontal accordion with vertical text, sans images. Stay tuned for part 2, where I discuss cross-browser application (this only works properly in Firefox, Chrome & Safari) and graceful degradation, and part 3: WordPress!

Edit: I still haven’t been able to get my Windows virtual machine up and running since my hard drive crash, so perhaps I’ll do the WordPress first. Or you’ll just have to wait… I can’t find my Windows install disks :(


This entry was posted in Tutorials. Bookmark the permalink.

9 Responses to Horizontal Accordion Slider with Vertical Text

  1. Pingback: 40 Best Web Design And Development Tutorials From August 2011 | stylishwebdesigner

  2. Pingback: 40 Best Web Design And Development Tutorials From August 2011 | Free 9 Spot

  3. Pingback: Twenty Top Advanced CSS Tutorials » HTML & CSS, Web Design » Design Festival

  4. Pingback: I’m reading Twenty Top Advanced CSS Tutorials | william j. moner

  5. tania says:

    Thank you for this tutorial. Long time I was looking for this trick.

  6. Jony says:

    Wow! It’s really great. Thanks for sharing it with example. I must use it in my coming projects. Once again thank you so much.

  7. mzer says:

    thanks for the tutorial. How browser compliant is this? I was using IE7 and the rendering is different to when i used firefox!!

  8. Titus says:

    Hey, awesome tut, is there a way to make a specific tab to be active instead of the default one.

  9. Titus says:

    Oh never mind just added $(‘#slide-1’).trigger(‘open’); on the bottom of the $(document).ready function 😀 and it did the trick.

Leave a Reply to tania Cancel reply

Your email address will not be published. Required fields are marked *