I wish to have a similar effect to jQuery slidedown but without using jQuery or any other libary. I know it\'s \"possible\" as anything in jQuery can be don
Since we are in 2014, why not use CSS transitions and just change the height property of the element? Fiddle
CSS:
.wrapper {
transition:height 1s ease-out;
height:0;
overflow:hidden;
}
HTML:
<div id="wrapper">
//content
</div>
JAVASCRIPT:
document.getElementById("wrapper").style.height = //content height +"px";
So we're in 2020 and it's even more obvious now we should rely on CSS effects for this kind of animations.
However, a valid point has been made against this answer - you need to specify the height of the element that you're animating in the js code, and you might not know this value in advance.
So six years later, I'm adding a couple extra lines of code to cover this case.
So if we use the same CSS and HTML as in our old 2014 example, this is the new JS. New Fiddle!
const slideDown = elem => elem.style.height = `${elem.scrollHeight}px`;
slideDown(document.getElementById("wrapper"));
As an improvement to @Ruben Serrate solution which misses the use case for unknown height, I've created this using CSS3 and javascript (no jQuery):
/**
* getHeight - for elements with display:none
*/
getHeight = function(el) {
var el_style = window.getComputedStyle(el),
el_display = el_style.display,
el_position = el_style.position,
el_visibility = el_style.visibility,
el_max_height = el_style.maxHeight.replace('px', '').replace('%', ''),
wanted_height = 0;
// if its not hidden we just return normal height
if(el_display !== 'none' && el_max_height !== '0') {
return el.offsetHeight;
}
// the element is hidden so:
// making the el block so we can meassure its height but still be hidden
el.style.position = 'absolute';
el.style.visibility = 'hidden';
el.style.display = 'block';
wanted_height = el.offsetHeight;
// reverting to the original values
el.style.display = el_display;
el.style.position = el_position;
el.style.visibility = el_visibility;
return wanted_height;
};
/**
* toggleSlide mimics the jQuery version of slideDown and slideUp
* all in one function comparing the max-heigth to 0
*/
toggleSlide = function(el) {
var el_max_height = 0;
if(el.getAttribute('data-max-height')) {
// we've already used this before, so everything is setup
if(el.style.maxHeight.replace('px', '').replace('%', '') === '0') {
el.style.maxHeight = el.getAttribute('data-max-height');
} else {
el.style.maxHeight = '0';
}
} else {
el_max_height = getHeight(el) + 'px';
el.style['transition'] = 'max-height 0.5s ease-in-out';
el.style.overflowY = 'hidden';
el.style.maxHeight = '0';
el.setAttribute('data-max-height', el_max_height);
el.style.display = 'block';
// we use setTimeout to modify maxHeight later than display (to we have the transition effect)
setTimeout(function() {
el.style.maxHeight = el_max_height;
}, 10);
}
}
Here is the demo: http://jsfiddle.net/pgfk2mvo/
Please let me know if you can find any improvements to this as I always try to improve my code. Happy coding ! :D
Have a look at the jQuery source for that effect (slideDown
calls show
).
Here's the solution to use slideDown, slideUp animation with an unknown content height element. https://jsfiddle.net/gebpjo1L/18/
It based on the CSS 3 height animation, but the animation requires a specified content height, so you need to get the height of the content via JavaScript before you expanding it.
var container = document.querySelector('div')
var button = document.querySelector('button')
button.addEventListener('click', () => {
/** Slide down. */
if(!container.classList.contains('active')) {
/** Show the container. */
container.classList.add('active')
container.style.height = "auto"
/** Get the computed height of the container. */
var height = container.clientHeight + "px"
/** Set the height of the content as 0px, */
/** so we can trigger the slide down animation. */
container.style.height = "0px"
/** Do this after the 0px has applied. */
/** It's like a delay or something. MAGIC! */
setTimeout(() => {
container.style.height = height
}, 0)
/** Slide up. */
} else {
/** Set the height as 0px to trigger the slide up animation. */
container.style.height = "0px"
/** Remove the `active` class when the animation ends. */
container.addEventListener('transitionend', () => {
container.classList.remove('active')
}, {once: true})
}
})
div {
transition: height .5s ease;
overflow : hidden;
}
div:not(.active) {
display: none;
}
<div>
I'm an unknown content height element.
I'm an unknown content height element.
I'm an unknown content height element.
I'm an unknown content height element.
I'm an unknown content height element.
I'm an unknown content height element.
I'm an unknown content height element.
I'm an unknown content height element.
I'm an unknown content height element.
I'm an unknown content height element.
I'm an unknown content height element.
I'm an unknown content height element.
</div>
<button>Slide Toggle</button>
this pure js solution doesn't require knowing the the max-height beforehand, and uses css-transitions.
it will set max-height to 2x browser window's height during transition, and then the remove max-height after the transition is done.
full slideDown, slideUp demo @ https://kaizhu256.github.io/node-swagger-lite/build..alpha..travis-ci.org/app/index.html
css
.swggAnimateSlide {
overflow-y: hidden;
transition: all 500ms linear;
}
.swggAnimateSlideUp {
border-bottom: 0 !important;
border-top: 0 !important;
margin-bottom: 0 !important;
margin-top: 0 !important;
max-height: 0 !important;
padding-bottom: 0 !important;
padding-top: 0 !important;
}
js
domAnimateSlideDown = function (element) {
/*
* this function will slideDown the dom-element
*/
if (element.style.maxHeight || element.style.display !== 'none') {
return;
}
element.classList.add('swggAnimateSlideUp');
element.classList.add('swggAnimateSlide');
element.style.display = '';
setTimeout(function () {
element.style.maxHeight = 2 * window.innerHeight + 'px';
element.classList.remove('swggAnimateSlideUp');
}, 50);
setTimeout(function () {
element.style.maxHeight = '';
element.classList.remove('swggAnimateSlide');
}, 500);
};
domAnimateSlideUp = function (element) {
/*
* this function will slideUp the dom-element
*/
if (element.style.maxHeight || element.style.display === 'none') {
return;
}
element.style.maxHeight = 2 * window.innerHeight + 'px';
element.classList.add('swggAnimateSlide');
setTimeout(function () {
element.classList.add('swggAnimateSlideUp');
element.style.maxHeight = '0px';
}, 50);
setTimeout(function () {
element.style.display = 'none';
element.style.maxHeight = '';
element.classList.remove('swggAnimateSlide');
element.classList.remove('swggAnimateSlideUp');
}, 500);
};
Here is a nice little piece of code I wrote from scratch.
It is purely time based.
var minheight = 20;
var maxheight = 100;
var time = 1000;
var timer = null;
var toggled = false;
window.onload = function() {
var controller = document.getElementById('slide');
var slider = document.getElementById('slider');
slider.style.height = minheight + 'px'; //not so imp,just for my example
controller.onclick = function() {
clearInterval(timer);
var instanceheight = parseInt(slider.style.height); // Current height
var init = (new Date()).getTime(); //start time
var height = (toggled = !toggled) ? maxheight: minheight; //if toggled
var disp = height - parseInt(slider.style.height);
timer = setInterval(function() {
var instance = (new Date()).getTime() - init; //animating time
if(instance <= time ) { //0 -> time seconds
var pos = instanceheight + Math.floor(disp * instance / time);
slider.style.height = pos + 'px';
}else {
slider.style.height = height + 'px'; //safety side ^^
clearInterval(timer);
}
},1);
};
};
Test it here: http://jsbin.com/azewi5/5