By Craig Buckler

How to Create a CSS3-Only Horizontal Accordion Using the :target Selector

By Craig Buckler

The CSS3 :target selector is incredibly powerful and allows us to create attractive widgets which would have required ninja-like JavaScript skills a few years ago. We’ve already built a tab control and a vertical accordion. In this post, we’ll create a horizontal accordion using the same HTML5 markup.

View the demonstration page…

The solution works in IE9, Chrome, Firefox, Safari and Opera and doesn’t require JavaScript or images. Again, it fails miserably in IE6, 7 and 8 so you either need a JavaScript shim such as selectivizr or some other fallback.


Here’s a reminder of the HTML5 code. It’s identical to our vertical accordion: there are a number of section elements with clickable headings contained in the initial h2 tag:

<article class="accordion">

	<section id="acc1">
		<h2><a href="#acc1">Title One</a></h2>
		<p>This content appears on page 1.</p>
	<section id="acc2">
		<h2><a href="#acc2">Title Two</a></h2>
		<p>This content appears on page 2.</p>
	<section id="acc3">
		<h2><a href="#acc3">Title Three</a></h2>
		<p>This content appears on page 3.</p>
	<section id="acc4">
		<h2><a href="#acc4">Title Four</a></h2>
		<p>This content appears on page 4.</p>
	<section id="acc5">
		<h2><a href="#acc5">Title Five</a></h2>
		<p>This content appears on page 5.</p>



The CSS is a little more complex but it’s worth it. First we style our outer article container:

	display: block;
	width: 43em;
	margin: 0 auto;
	background-color: #666;
	overflow: auto;
	border-radius: 5px;
	box-shadow: 0 3px 3px rgba(0,0,0,0.3);

Each section starts in its closed state; they’re floated to the left and have a width of 2em. Overflow is set to hidden and we’re also making the text color the same as the background so they effectively look like solid blocks without content:

article.accordion section
	position: relative;
	display: block;
	float: left;
	width: 2em;
	height: 12em;
	margin: 0.5em 0 0.5em 0.5em;
	color: #333;
	background-color: #333;
	overflow: hidden;
	border-radius: 3px;

Now for some nasty prefixed CSS3! Each h2 title is rotated 90° counter-clockwise using a transform and absolutely positioned over the closed section:

article.accordion section h2
	position: absolute;
	font-size: 1em;
	font-weight: bold;
	width: 12em;
	height: 2em;
	top: 12em;
	left: 0;
	text-indent: 1em;
	padding: 0;
	margin: 0;
	color: #ddd;
	-webkit-transform-origin: 0 0;
	-moz-transform-origin: 0 0;
	-ms-transform-origin: 0 0;
	-o-transform-origin: 0 0;
	transform-origin: 0 0;
	-webkit-transform: rotate(-90deg);
	-moz-transform: rotate(-90deg);
	-ms-transform: rotate(-90deg);
	-o-transform: rotate(-90deg);
	transform: rotate(-90deg);

article.accordion section h2 a
	display: block;
	width: 100%;
	line-height: 2em;
	text-decoration: none;
	color: inherit;
	outline: 0 none;

We can now ‘open’ the active section using the :target selector. The section width and colors are changed and the title is moved back to the top:

article.accordion section:target
	width: 30em;
	padding: 0 1em;
	color: #333;
	background-color: #fff;

article.accordion section:target h2
	position: static;
	font-size: 1.3em;
	text-indent: 0;
	color: #333;
	-webkit-transform: rotate(0deg);
	-moz-transform: rotate(0deg);
	-ms-transform: rotate(0deg);
	-o-transform: rotate(0deg);
	transform: rotate(0deg);

That’s fine, but a CSS3 transition makes it look fantastic:

article.accordion section,
article.accordion section h2
	-webkit-transition: all 1s ease;
	-moz-transition: all 1s ease;
	-ms-transition: all 1s ease;
	-o-transition: all 1s ease;
	transition: all 1s ease;

View the demonstration page…

It’s a shame IE6, 7 and 8 users can’t use the widget. IE9 users won’t see animation either. But you’d need a lot of time and patience to achieve the same effect using JavaScript! Have fun with it.

  • Matt

    A major drawback to this technique: when following a link to a fragment identifier, the browser will scroll to where the element is on the page. This can be observed if you squish the demonstration page into a tiny window so there is a vertical scroll bar; now clicking the according causes it to scroll to the top of the viewport. The same is true if you use this technique for tabs.

    “Not such a big deal” I hear you cry! If this widget is ever placed on a page that scrolls it pretty much makes the technique unusable. A fix would be to use preventDefault with JavaScript – but now, if we have JavaScript available, we might as well use JavaScript to switch out the tabs/according sections too… I’d really like to use this technique, but it’s just not (currently) viable.

    • Thanks Matt. It will jump to the correct part of the page, but how is that different to using a #fragment in any link? I agree that a little JS would make it better, though.

  • sathish


  • Three things, and I’m done with this “should be javascript not CSS”.

    1. The fact that it relies on fragments, it makes for a frustrated user. We’ve been over this one and I didn’t get a logical reason as to why it is desirable for the user to look at this one as a feature. For me it’s a clear drawback, and even more, it’s inconsistent behavior if you don’t provide TOCs for fragments in every one of your pages.

    2. A quick web search for “jquery plugin horizontal accordion” reveals at least a few quality results that stand against your “But you’d need a lot of time and patience to achieve the same effect using JavaScript!”

    3. I have no strong opinion about the use of this CSS and :target solution by anyone that wants to. I have a strong opinion when it come to categorizing this working compromise as a natural evolution. This programmatic behavior belongs in javascript while CSS should do presentation better. The link hover/active example you gave is not applicable by similarity since in that case CSS doesn’t decide what the link does, it only decides how it looks like.

    Done done and done :)

    • Hi again!

      Remember you can, if desired, add TOCs or links anywhere on the page to a section within the accordion. I agree that the HTML is coded differently — and perhaps less semantically — than you’d normally see for a tab-like control. Whether that’s a problem will depend on your use-case.

      Do the JavaScript versions you discovered use CSS3? You’d have a tough time implementing rotations and other effects without them.

      I don’t think we’ll ever determine whether this is or isn’t programmatic behavior. But I will leave you with this: it is a far simpler solution.

      • It appears to me that in the heat of discussion I forgot to acknowledge your hard work in putting together these CSS3 techniques. Sorry for that :) Nice work!

      • You’re welcome, itmitica.

  • RidleyO

    Fun experiment but the current state is not usable in production, as it doesn’t degrade in ie8. (Unless your audience is sure not to use that browser….)

    • It’ll work if you add a JavaScript shim such as selectivizr.

  • noname

    Amazing css3 goodness, looking forward of using these techniques
    Thank you


    nice clas

  • Joseph Spears

    Any way to change this to a click instead of hover rollout?

Get the latest in Front-end, once a week, for free.