Cross Browser Pure CSS3 Vertical Accordion

I was studying various CSS accordions and found that better ones are built using CSS3; as expected, they didn’t work in Internet Explorer. More noticeably, they didn’t even degrade properly. This was mainly due to use of CSS3 “:target” pseudo class to open accordion panels.

So why every CSS3 accordion I came across used “:target” pseudo class. There are two main reasons: opening an accordion with a click (“target”) is much better than opening it on mouse over (“hover”); and it provides RESTful URLs for each panel. Sounds like solid reasons – but there are serious drawbacks, which can’t be overlooked:

  • May Cause Usability Nightmare
    Unless your accordion is always above the fold and user cannot scroll your page; pure CSS accordions using “target” will cause usability nightmare by jumping to top with every click.
  • Not Ready For Production Environment
    CSS3 “:target” pseudo class is not yet supported in any version of Internet Explorer – which occupies big share of web browser market. This fact simply means we cannot use these CSS3 accordions in production.

Lets Build Our Own

So lets build our own CSS3 accordion that should work on all modern browsers and degrade gracefully for less fortunate ones. To achieve this we will use “hover” instead of “target”.

We will be using CSS3 to add transition effect and you can even add other cool CSS3 features like gradients, font-face, etc to jazz it up. But the main structure and behavior will be written in cross-browser CSS that will work in IE7+ and all other modern browsers.

View Demo Now Download Files

Our accordion will degrade to an unordered list in IE6 (which will be completely untouched by our CSS). You can use conditional CSS to style unordered list for IE6 or older browsers however you like.

Accordion Markup

Nothing much here, we are going to use simple markup that is self explanatory:

<div class="verticalaccordion">
<ul>
	<li>
        <h3>Heading 1</h3>
		<div>Content For Panel 1.</div>
	</li>
	<li>
        <h3>Heading 2</h3>
		<div>Content For Panel 2</div>
	</li>
	<li>
        <h3>Heading 3</h3>
		<div>Content For Panel 3.</div>
	</li>
	<li>
        <h3>Heading 4</h3>
		<div>Content For Panel 4</div>
	</li>
</ul>
</div>

Note:

  • Each “li” element inside unordered list represents a panel
  • Each “h3” element inside a list item represents panel head
  • Each “div” element inside a list item represents panel content

Styling Accordion Structure

With our markup all ready, it is fairly easy to style the structure. Take a look at following CSS – it will create an accordion with all its panels collapsed:

.verticalaccordion>ul {
    margin: 0;
    padding: 0;
    list-style:none;
    width: 500px;
}

.verticalaccordion>ul>li {
    display:block;
    overflow: hidden;
    margin: 0;
    padding: 0;
    list-style:none;
    height:40px;
    width: 500px;

    /* Decorative CSS */
    background-color:#f0f0f0;
}

.verticalaccordion>ul>li>h3 {
    display:block;
    margin: 0;
    padding:10px;
    height:19px;

    /* Decorative CSS */
    border-top:#f0f0f0 1px solid;
    font-family: Arial, Helvetica, sans-serif;
    text-decoration:none;
    text-transform:uppercase;
    color: #000;
    background: #cccccc;
}

.verticalaccordion>ul>li>div {
    margin:0;
    overflow: auto;
    padding:10px;
    height:220px;
}

Note:

  • Child Combinators
    I have purposely used child combinators to make sure that CSS applies only to the elements used in creating accordion structure and not inherited by elements that are used in accordion content.
  • Default State: Panels
    Since we are not using “:target” pseudo class, we are not able to specify accordion’s state. That’s why we have to set all panels in collapsed state by default. This is done by setting height of “li” equal to the height of “h3” elements (i.e., total height of each panel is equal to the height of its head). Overflow in “li” is set to hide, so that “div” element containing the content is not visible by default.
  • Default State: Panel Head
    There is not much to note here except that total height of “h3” element is calculated by adding height, padding-top, padding-bottom and height of the border (if any).
  • Panel Content
    For panel content “div”, you may want to note that overflow is set to “auto”. This will add scrolling bar(s) if content doesn’t fit inside the content area. Total height (height + padding-top + padding-bottom) of the content area is determined by using this formula: accordion-height - (number-of-panels x height-of-panel-head).

Styling Accordion Behavior

As discussed earlier, our accordion will respond when mouse is moved over it using “hover”. Adding following CSS will do the trick:

.verticalaccordion>ul>li:hover {
    height: 280px;
}

.verticalaccordion:hover>ul>li:hover>h3 {
    /* Decorative CSS */
    color:#fff;
    background: #000000;
}

.verticalaccordion>ul>li>h3:hover {
    cursor:pointer;
}

Note:

  • Opening Panel With Hover
    In order to add behavior to our accordion – all we need to do is increase height of the Panel (“li” element) when mouse is moved over it. Panel height is determined by using this formula: accordion-height – ((number-of-panels – 1) x height-of-panel-head).
  • Highlighting Current Panel Head
    We have highlighted current or open panel by changing the background property of the “h3” element when mouse moves over “li”. It is important to do this on “li:hover” instead of “h3:hover”, because you want to highlight panel head even mouse is hovering over its content.
  • Changing Mouse Pointer
    Since we are not using anchors, we have changed mouse pointer using CSS when mouse hovers over “h3” element.

Adding Transition Effect

By adding structure and behavior, we have successfully created pure CSS vertical accordion. It looks and works perfectly in all modern browsers including IE7+.  Now its time to use CSS3 to do something that is not possible with older versions of CSS. The most essential CSS3 feature that we need to add is transition effect. Lets just do it, by adding following style to our panels (i.e., “li” element):

transition: height 0.3s ease-in-out;
-moz-transition: height 0.3s ease-in-out;
-webkit-transition: height 0.3s ease-in-out;
-o-transition: height 0.3s ease-in-out;

CSS3 transition effect is currently available in Safari, Chrome and Opera. It will soon be available on Firefox with version 3.7. IE7 and IE8 will continue to display CSS accordion without any transition effect.

Sprinkling Little Bit of Additional CSS3 Magic

You can add several other CSS3 effects like border-radius, text-shadow, font-face,etc to enhance the accordion. To get you started, here is some CSS3 that will add gradient effect to the panel head (i.e., “h3” element):

background: -moz-linear-gradient( top, #999999, #cccccc);
background: -webkit-gradient(linear, left top, left bottom, from(#999999), to(#cccccc));
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ff999999, endColorstr=#ffcccccc); /* IE 7 */
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#ff999999, endColorstr=#ffcccccc)";   /* IE 8 */

The above lines of code will add gradient effect to panel heads in all browsers (including IE7 & 8) except for Opera. We also need to add gradient effect to panel heads, when mouse is over the panel (i.e., li:hover>h3). To achieve this add following CSS3 and IE filters:

background: -moz-linear-gradient( top, #454545, #000000);
background: -webkit-gradient(linear, left top, left bottom, from(#454545), to(#000000));
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ff454545, endColorstr=#ff000000); /* IE 7 */
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#ff454545, endColorstr=#ff000000)";   /* IE 8 */

Note: you can also add a background image here to display gradient effect, which will also work in Opera and older browsers. In this case you may also get rid of IE filters.

Complete Code

That’s it – we are done. This is how complete CSS file will look like:

.verticalaccordion>ul {
    margin: 0;
    padding: 0;
    list-style:none;
    width: 500px;
}

.verticalaccordion>ul>li {
    display:block;
    overflow: hidden;
    margin: 0;
    padding: 0;
    list-style:none;
    height:40px;
    width: 500px;

    /* Decorative CSS */
    background-color:#f0f0f0;

    /* CSS3 Transition Effect */
    transition: height 0.3s ease-in-out;
    -moz-transition: height 0.3s ease-in-out;
    -webkit-transition: height 0.3s ease-in-out;
    -o-transition: height 0.3s ease-in-out;
}

.verticalaccordion>ul>li>h3 {
    display:block;
    margin: 0;
    padding:10px;
    height:19px;

    /* Decorative CSS */
    border-top:#f0f0f0 1px solid;
    font-family: Arial, Helvetica, sans-serif;
    text-decoration:none;
    text-transform:uppercase;
    color: #000;
    background: #cccccc;

    /* CSS3 Gradient Effect */
    background: -moz-linear-gradient( top, #999999, #cccccc);
    background: -webkit-gradient(linear, left top, left bottom, from(#999999), to(#cccccc));
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ff999999, endColorstr=#ffcccccc); /* IE 7 */
    -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#ff999999, endColorstr=#ffcccccc)";   /* IE 8 */
}

.verticalaccordion>ul>li>div {
    margin:0;
    overflow: auto;
    padding:10px;
    height:220px;
}

.verticalaccordion>ul>li:hover {
    height: 280px;
}

.verticalaccordion:hover>ul>li:hover>h3 {
    /* Decorative CSS */
    color:#fff;
    background: #000000;

    /* CSS3 Gradient Effect */
    background: -moz-linear-gradient( top, #454545, #000000); /* FF, Flock */
    background: -webkit-gradient(linear, left top, left bottom, from(#454545), to(#000000)); /* Safari, Chrome */
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ff454545, endColorstr=#ff000000); /* IE 5.5 - IE 7 */
    -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#ff454545, endColorstr=#ff000000)";   /* IE 8 */
}

.verticalaccordion>ul>li>h3:hover {
    cursor:pointer;
}

Note:

  • You must specify DOCTYPE in your web page in order for this CSS to work in IE.
  • You can have more than one Accordion in a single page. If they have different properties, you can simply copy the above code, give different class name, and change the properties.
  • If number of panels are different from our example, you will need to adjust “height” properties in the CSS accordingly.
  • This accordion uses CSS “hover” and works with a mouse. (Point added after reading concerns in comments below – Sorry for taking this point for-granted)

Now What?

Well the natural next step is to experiment, play around and enhance further. But you may even be wondering about “Horizontal Accordion“. Horizontal accordion is a different beast, which I will be sharing with you in next few days. I have already completed the demo, but I still need to write the article. It uses same markup enabling you to switch from vertical to horizontal accordion by simply changing the class name. So stay tuned if you are interested.

View Demo Now Download Files

I hope you have enjoyed this post and found it to be useful. I am looking forward to reading your feedback, opinion and suggestions.

Update: Cross Browser Pure CSS3 Horizontal Accordion

Stay Updated

If you found this post useful, consider subscribing to our RSS Feed! You can also stay updated by following us on Twitter and Facebook or by subscribing to our FriendFeed.

Bookmark / Share

Bookmark and Share

Read More

SIMILAR/RELATED POSTS:

PREVIOUS POST:

NEXT POST:

Reader Comments

24 Responses to “Cross Browser Pure CSS3 Vertical Accordion”
  1. David says:

    Good read, shame the :hover class don’t work with handheld devices like the iPhone.

    • Lars-Eberhard Schmidt says:

      Hello, David,

      But of course, it does. You just need to wrap the tag with a tag and adapt the CSS accordingly.

      Oh, and increase the transition time to 0.5s!

      Have fun.

      • Lars-Eberhard Schmidt says:

        Hello, David,
        hello, myself,

        So, no HTML tags here, OK. Please wrap the “li” list tag in HTML with a “span” tag which contains an “onclick” attribute and a value “void(0)” for it. Close your “/span” tag after the closing “/li” tag.

        Adapt your CSS file then in places where needed: e. g. “.accordion>ul>span>li”, you have this additional “>span” in there now which was not there in the first place.

        On iPhone it works with iOS 4.2 beta 3, but since you cannot have the height set to “auto” but need a precise value for the height of the “div” containing the accordion cell content, the accordion will open and close but cannot do this “-webkit-transition” animated. At least I did not have any luck with that.

        Have fun.

  2. Teylor Feliz says:

    Very good tutorial, thanks for sharing!

  3. Bill says:

    Nice!
    (why wouldn’t it work with the iPhone, if it works with webkit?)

  4. Ryan says:

    Nice attempt but my CSS accordion (which uses :target), http://www.thecssninja.com/css/accordian-effect-using-css, already has a working solution for IE6+, http://www.thecssninja.com/demo/css_accordion/ie_solution.html, which uses hover and active so when a user clicks a title it will stay open even after the cursor has left the hover area. For the better browsers it uses target.

    • Saud Khan says:

      Ryan,

      Thanks for sharing links. but following issues caused by “:target” remains:

      (1) It jumps around if your accordion is not above the fold, and there are scroll bars in browser window.

      (2) Not major issue, but it won’t allow multiple instances using same CSS.

      Having said this. I am also not claiming that CSS accordion presented in this article is a perfect solution. I just believe it has better chance of being used in production than other “:target” based CSS accordions.

      • Bryan Watson says:

        I’m going to have to side with Ryan’s approach on this one, especially regarding using such a technique in production.

        The :hover method is just not good for UX. The main problem is that there is no way to keep the content visible without having your mouse inside the element. This poses multiple usability issues, but also creates a lot of confusion for non-webkit users that can’t see the appropriate transitions.

        Also, the markup and CSS can be cleaned up quite a bit. For example, it’s not necessary to use a wrapper div in this situation.

        Another issue that isn’t tackled with this solution, is that the height is not flexible. If you have one “level” with a lot of content, the other levels are going to be forced to have a lot of wasted white-space.

        “(1) It jumps around if your accordion is not above the fold, and there are scroll bars in browser window. ”

        I think this is even more of an issue with your solution. In regards of accessibility, if your accordion was near the bottom of a site and the user does not have a scroll wheel, it’s difficult to navigate to view the content in the bottom “levels”. Since the accordion collapses on mouse-out, there is no way to effectively use the scroll bar in the browser window, and therefore renders the accordion useless.

        • Saud Khan says:

          Bryan,

          Thanks for your opinion. But with all due respect, I disagree to several statements:

          (1) Your theory of confusing users who can’t see transition effect also applies to Ryan’s accordion – it has nothing to do with “:target” or “:hover”.(also I don’t see how it confuses users if they don’t see the transition effect – you can always have an accordion without any animation)

          (2) Your comment about extra wrapper div. Well it is necessary because I am using CSS Child Combinator. This allows our accordion to contain any element including another unordered list. If you have used Ryan’s accordion, try adding a definition list as content in one of its panels – you will be surprised to see another accordion created inside the panel.

          (3) Your comment about having flexible height is correct. All panels in our accordion will have same height. But if you add large content it will automatically add scrollbars, enabling users to see the content. But if you are looking for an accordion panel that allows flexible height, you certainly can’t use this one.

          (4) For your last point, I will simply request you to try to use CSS3 accordion using “:target” in a browser window that is not above the fold and has scrollbars. I am sure you will rethink about its usability.

          Finally, I must state that I personally like Ryans work and I didn’t mean to undermine his work in any way with my comments. I had to refer to it only because this thread seems to be comparing these two accordions.

  5. Can Aydoğan says:

    Great tutorial. Thanks for sharing.

  6. Deepu Balan says:

    Really interesting stuff… Thanks for sharing this well written tutorial… Post more :-)

    -Deepu

  7. That is an fascinating accordion that does not use jQuery – great work.

  8. Derrick says:

    Very nice work! I’ll be glad when more browsers start supporting these features. Better yet, I will be happy when all people start using nice, CSS3 compliant browsers!

  9. Richard says:

    I appreciate the demo, but how about keyboard and/or screen reader accessibility? As far as I can tell, this example wouldn’t work without a mouse.

    • Saud Khan says:

      Yes, anything that depends on “hover” will not work without a mouse.You should take these solutions as a starting point – mix a little bit of JavaScript to find perfect solution that works everywhere.

  10. 4 weeks ago we did something similar called – Sliding Menu based on CSS3 Transition (no images)!

  11. tarah says:

    great tutorial, it’d be nice if it worked on mobile. btw, button-view-demo.png is missing the letter “i” in the word “view”. ;)

    cheers!

    • W3Avenue Team says:

      Thanks a lot, fixed it. This is classic example, why someone else should do QA for you :)

      Once again thanks, really appreciate your support.

  12. Sivaranjan says:

    Whoa! I didnt know I could do this much with CSS and HTML! Thanks for writting such an amazing piece of tutorial. I am gonna need this. Can I add this article to my CSS aggregator site ?

  13. chavada bipin says:

    this site is very beautiful site for web developer
    and person who want’s to learn web developing.

  14. RedGen says:

    I haven’t yet tried the code (i’ve tried about 15 already today with varying effectiveness – thanks to Sharepoint 2003 glitching even the simplest accordion scripts) but why would you design CSS for only IE7+ when most larger organisations are still stuck in IE6?

    I know we all want to work to what should be, but sadly many of us still have to struggle on with a different reality.

  15. This is a great tutorial! Everything is working great! Thanks for sharing.

  16. Nick says:

    Thank you so much! This helped a lot.

Leave Comment

 
 

Stay Updated, Subscribe to RSS Feed

 
 
 
 

Blogroll

 

Sponsored Links

  • List MLS Multiple Listing Service
  • BlueHost coupon