Create the accordion effect using CSS3
Recently I have been playing around with CSS transitions and animations as implemented in webkit based browsers such as Safari and Chrome. They have been submitted to the W3C for consideration in the CSS3 spec so hopefully we should see more browsers support this soon, Firefox 3.5 supports CSS transforms which was developed by the webkit people to work alongside CSS animations & transitions.
To continue my effort to accomplish tasks in CSS that are usually reserved for JavaScript, such as my Futurebox and CSS based iPhone orientation detection. I have developed a CSS based version of the popular “accordion effect” that utilises the webkit CSS transitions. Like the Futurebox demo I’m utilising the CSS3 :target pseudo class to know which item to show based the URI fragment identifier (the # in the url).
It should be noted that this works best in a webkit based browser such as Safari 3+, Chrome or iPhone. Other browsers that support the :target pseudo class will still function on the core level but won’t animate the showing and hiding. The following browsers have been tested and work with this demo.
- Firefox 1.5+
- Opera 9.6+
- Safari 3+
- Chrome 1+
- IE6+ – IE solution
The xhtml
<p>
We setup the accordion using a <a href="https://www.w3.org/MarkUp/html3/deflists.html">definition list</a> to create the foundation so we can show and hide the definition data (dd) tag when the user clicks the anchor link inside the definition title (dt) tag.
</p>
<h2 class="subtitle02">
The CSS
</h2>
<pre lang="css">
dl { padding: 10px; min-width: 960px; } dl dt { -webkit-border-radius: 5px; -moz-border-radius: 5px; border: 1px solid #cccccc; margin: 0; } dl dt a { color: #ffffff; font-weight: bold; text-decoration: none; padding: 10px; display: block; } dl dd { margin: 0; height: 0; overflow: hidden; -webkit-transition: height 1s ease; } dl dd p { padding: 10px; margin: 0; } dl dd:target { height: auto; }
@media (-webkit-transition) { dl dd:target { height: 6.667em; } }
<p>
Pretty simple CSS involved, the <em>dd</em> tag is hidden by setting the <em>height</em> to 0 and the <em>overflow</em> to hidden.
</p>
<pre lang="css">
-webkit-transition: height 1s ease;
<p>
This property on the <em>dd</em> tag lets webkit browsers know we wish to transition the height value over 1 second period using the <em>ease</em> timing function this transition will only happen when the <em>height</em> of the <em>dd</em> tag is changed. We can also express this in a long hand version.
</p>
<pre lang="css">
-webkit-transition-property: height; -webkit-transition-duration: 1s; -webkit-transition-timing-function: ease;
<p>
To change the height we use the <em>:target</em> pseudo class to set the height of the dd tag to auto so the right content will show based the URI fragment identifier. For webkit browsers it’s a little different.
</p>
<h2 class="subtitle02">
Webkit media queries
</h2>
<p>
In webkit browsers there are additional <a href="https://webkit.org/specs/MediaQueriesExtensions.html">media queries available</a> so we can target browsers that support the extended features such as transitions and not affect other browsers. In this demo I use the <em>@media (transition)</em> media query.
</p>
<p>
Webkit implements this feature by using their -webkit vendor extension so the media query looks like the following
</p>
<pre lang="css">
@media (-webkit-transition) { dl dd:target { height: 6.667em; } }
<p>
Unfortunately setting the height of the <em>dd</em> tag to <em>auto</em> will not make it animate although this would be ideal and much more capable of catering for different sized content it’s not possible at the moment. For now we have to set the height to an actual value, to keep the height in line with any text resizing I set the height using em based value so if the user has larger text the height will adjust and won’t cut of any content. The height is 80px we divide by the base font size, which is 12, and we get 6.667em.
</p>
<h2 class="subtitle02" id="ie-solution">
What about IE
</h2>
<p>
Unfortunately IE doesn’t support the <em>:target</em> pseudo class and won’t work as describe above, but that didn’t stop me! Take a look at working example that functions in IE6 and up.
</p>
<div class="resources01">
<a target="_blank" class="demo" title="Accordion effect using CSS that works in IE6+" href="https://ryanseddon.com/demo/css_accordion/ie_solution.html">View a live demo</a> <a target="_blank" class="demo source" title="Download the source of the CSS IE accordion demo" href="https://ryanseddon.com/demo/css_accordion/css_accordion_ie.zip">Download the source files</a>
</div>
<p>
This is quite hacky and involves a bit of IE conditional comments.
</p>
<h2 class="subtitle02">
IE xhtml
</h2>
<pre lang="html4strict">
<a href="#Section1">
<!--<![endif]-->Section 1
<!--[if !IE]>-->
</a>
<!--<![endif]-->
</p>
...
<p>
As you can see there is <a href="https://msdn.microsoft.com/en-us/library/ms537512%28VS.85%29.aspx">conditional comments</a> so I can wrap the <em>dt</em> and <em>dd</em> tag in an anchor so we can get it functioning in IE using the following CSS. I also use the conditional comments to hide the anchor that appears in the <em>dt</em> tag only for IE browsers. IE6 was not functioning with just the anchor around the <em>dd</em> & <em>dt</em> so I added a <em>div</em> inside the anchor. In IE6 the first anchor would surround all the items, the div fixes that. Demo, demo files and example code has been updated to reflect that.
</p>
<h2 class="subtitle02">
IE CSS
</h2>
<pre lang="css">
dl a.ie { text-decoration: none; } dl a.ie dd { display: none; }
/* Fix IE6 hover bug */ dl a.ie:hover { background-color: #606061 !important; }
dl a.ie dt { color: #ffffff; font-weight: bold; text-decoration: none; padding: 10px; display: block; }
dl a.ie:hover dd, dl a.ie:active dd, dl a.ie:focus dd { height: auto; color: #cccccc !important; display: block; }
<p>
Pretty simple stuff, set the <em>text-decoration</em> so the content isn’t underlined. We need to hide the <em>dd</em> tag as it causes issues in IE7 and below when trying to hover over any items below the first section. Next a <em>background-color</em> is applied to the <em>:hover</em> pseudo class of the surrounding anchor to fix an issue in IE6 that won’t trigger a hover unless something like a background-color is applied it. To make it work in IE we utilise the <em>:hover</em>, <em>:focus</em> and <em>:active</em> pseudo classes. That way when the user hovers in IE the content gets revealed, we also simulate a “click” by using the <em>:active</em> pseudo class. The :focus pseudo class allows us to make it work by using keyboard navigation, tabbing to the anchor will reveal the content. All the mark-up is XHTML 1.0 Strict complaint.
</p>
<p>
I think this is a pretty good attempt and best of all it works in all major browser so it can be potentially be used in a production environment.
</p>