accordion
by Joe Dooley
HTML
<div class="big-container">
<div class="foo">
<h2>Smooth Accordion</h2>
<p>Vestibulum rutrum, mi nec elementum vehicula, eros quam gravida nisl, id fringilla neque ante vel mi. Vestibulum rutrum, mi nec elementum vehicula, eros quam gravida nisl, id fringilla neque ante vel mi.</p>
<p>Vestibulum rutrum, mi nec elementum vehicula, eros quam gravida nisl, id fringilla neque ante vel mi. Vestibulum rutrum, mi nec elementum vehicula, eros quam gravida nisl, id fringilla neque ante vel mi. Vestibulum rutrum, mi nec elementum vehicula, eros quam gravida nisl, id fringilla neque ante vel mi. Vestibulum rutrum, mi nec elementum vehicula, eros quam gravida nisl, id fringilla neque ante vel mi.</p>
<p>Vestibulum rutrum, mi nec elementum vehicula, eros quam gravida nisl, id fringilla neque ante vel mi.</p>
<button id="open-nested">Open Inner Div</button>
<button id="close-nested">Close Inner Div</button>
<div class="inner-container">
<div class="bar">
<p>Vestibulum rutrum, mi nec elementum vehicula, eros quam gravida nisl, id fringilla neque ante vel mi. Vestibulum rutrum, mi nec elementum mi.</p>
</div>
</div>
</div>
</div>
<button id="open-main">Open Accordion</button>
<button id="close-main">Close Accordion</button>
SCSS
.big-container {
width : 400px;
overflow : hidden;
opacity : 0;
transition : height 3s, opacity 1s;
}
.foo {
padding : 10px;
}
.inner-container {
height : 0;
overflow : hidden;
transition : height 2s, opacity 1s;
opacity : 0;
}
.bar {
}
#open {
background : lightblue;
padding : 10px 10px;
border : none;
margin : 12px 0;
outline : none;
position : relative;
}
JavaScript
// main and nested container elements
var $main = $('.big-container');
var $nested = $('.inner-container');
// this has to be done at initialisation
var mainHeight = getMainHeight();
// flags for open/close state of containers
var mainOpen = false;
var nestedOpen = false;
// open main container
function openMain() {
if (!mainOpen) {
mainOpen = true;
$main.css({
height: mainHeight,
opacity: 1
});
}
}
// close main: have to also close nested container if it is open
function closeMain() {
if (mainOpen) {
nestedOpen = false;
// need to close nested container too
$nested.css({
height: 0,
opacity: 0
});
mainOpen = false;
// set height and opacity to 0
$main.css({
'height': 0,
opacity: 0
});
}
}
// have to work out initial height before opening
function getMainHeight() {
// set height to auto value, measure, then reset to 0
$main.css({
height: 'auto'
});
var height = $main.height();
$main.css({
height: 0
});
return height;
}
// open nested. Set height of main container to 'auto' to allow it resize when nested
// container opens. After nested container has opened, reset main container height
// back to numeric value.
function openNested() {
if (!nestedOpen) {
nestedOpen = true;
function afterTransition() {
var mainHeight = $main.height();
$main.css({
height: mainHeight
});
$nested[0].removeEventListener("transitionend", afterTransition);
}
$main.css({
height: 'auto'
});
$nested[0].addEventListener("transitionend", afterTransition, false);
$nested.css({
height: 100,
opacity: 1
});
}
}
// close nested container. Set main container height to 'auto' before closing to...