I'm trying to make an animation for sliding up and sliding down. To toggle parts of the page. When the height is "hardcoded" in CSS to 210px before rendering the page and I call the Javascript function from a button it all works.
But when I try to do this dynamically, with Javascript to keep "hardcoding" to a minimum. It still does the change to the height. But the transition effect does not happen.
Here is the code snippet to high light the problem. I don't understand as to why this difference sabotages the transition.
function slideUp() {
var target = document.getElementById("targetDiv");
target.style.height = "" + target.clientHeight+"px"; // taking the rendered height of the div and setting it in CSS to mimic the pre set height in CSS
target.style.transition = "height 1.0s ease-in 0s";
target.style.height = "0px";
}
.divStyle {
/* height: 200px; without this the animation does not work */
background: blue;
overflow: hidden;
}
<div id="targetDiv" class="divStyle">
random content
</div>
<button onclick="slideUp()"> Slide up </button>
Use of max-height combined with setTimeout "hack" worked for me:
function slideUp() {
var target = document.getElementById("targetDiv");
target.style.maxHeight = target.clientHeight + "px";
setTimeout(function() {
target.style.maxHeight = 0;
}, 10);
}
.divStyle {
background: blue;
overflow: hidden;
transition: max-height 1s ease-in 0s;
}
<div id="targetDiv" class="divStyle">
random content
</div>
<button onclick="slideUp()"> Slide up </button>
However, it is not a clean way. Think of using transform: scaleY(0) instead.
There are multiple ways to achieve the goal, in your case you just require to init the style which is supposed to change at the later time so just use window.onload and init the value.
var org = "";
window.onload = function() {
var target = document.getElementById("targetDiv");
org = target.clientHeight;
target.style.height = "" + target.clientHeight + "px";
}
function slideUp() {
var target = document.getElementById("targetDiv");
target.style.transition = "height 1.0s ease-in 0s";
if (target.clientHeight == org) {
target.style.height = "0px";
} else {
target.style.height = org + "px";
}
}
.divStyle {
/* height: 200px; without this the animation does not work */
background: blue;
overflow: hidden;
}
<div id="targetDiv" class="divStyle">
random content
</div>
<button onclick="slideUp()"> Slide up </button>
Just so that if anyone comes along here, the given answers are good, just not in the current case I need. The way I managed finally is as follows.
function slideDown( targetId ){
var target = document.getElementById(targetId);
target.style.height = target.children[0].clientHeight + "px";
}
function slideUp( targetId ) {
var target = document.getElementById(targetId);
target.style.height = "0px";
}
.parentDivStyle{
overflow: hidden;
transition: height 0.5s ease-in 0s;
height: 0px;
background: blue;
}
.childDivStyle {
background: green;
padding: 10px 10px 10px 10px;
}
<div id="parent" class="parentDivStyle">
<div class="childDivStyle">
random stuff
text text text...........
</div>
</div>
<button onclick="slideUp('parent')"> Slide Up </button>
<button onclick="slideDown('parent')"> Slide Down </button>
This was actually a comment in a deleted answer. Idk why it was deleted. Was useful.
As mentioned before: having a height/max-height value set to auto/none stops
the transition from working.
Rather than setting the max-height to a specified, larger than needed
max-height by guesswork (if set to really high number causes a delay in the
transition), I added transition and a max-height to the content wrapper instead,
and used JavaScript to read the actual height of the contents. This way the
wrapper max-height is set to the currently rendered height of its contents.
This gives it a fixed inline height.
The problem with this solution, is that if the user decides to resize his
window, into say, a narrower screen (i.e. rotating from landscape to portrait
mode on mobile), the fixed max-height causes to content to be cut-off. The
work-around for this is setting a setTimeout() function to set the max-height
of the wrapper back to none just after the transition has ended. (none is
the default, initial CSS value of the max-height property)
The same thing needs to happen before the "contracting" transition. The
wrapper's max-height needs to be a fixed value for the transition to work.
Therefore, the height needs to again be read from its contents (which might have
actually changed in the meantime), applied to the wrapper, then after a short
delay (50ms seemed to work in my case, and the delay wasn't noticeable) begin
the transition.
Here's an example that expands the div contents when a button is pressed:
HTML:
<div id="content-wrapper">
<div id="content">
<!-- a lot of text content -->
</div>
</div>
<button id="show-more" type="button">Show More</button>
CSS:
#content-wrapper {
/* Initial max-height, can be any value including 0 */
max-height: 270px;
overflow: hidden;
/* transition occurs on max-height change with specified delay; */
transition: max-height 0.7s;
}
#content {
/* This makes margin of the contents be respected by the container
i.e. the height of the container its childrens' margins */
overflow: hidden;
}
JS:
function resetHeight() {
// make max-height of wrapper responsive again
wrapper.style.maxHeight = "none";
}
function toggleText() {
// check if content-wrapper is open
if (wrapper.className.includes("open")) {
// if is open, close content-wrapper and set initial max-height to wrapper
let contentHeight = window.getComputedStyle(content).height;
// sets max-height back from none to computed content height
wrapper.style.maxHeight = contentHeight;
// give it some time to reset the transition trigger caused by previous statement
setTimeout(function() {
wrapper.classList.remove("open");
wrapper.style.maxHeight = "270px"; // reset to our initial max-height
button.textContent = "Show More";
}, 50)
} else {
// if not open, open content-wrapper then use content's height to set the
// max-height of wrapper
wrapper.classList.add("open");
let contentHeight = window.getComputedStyle(content).height;
wrapper.style.maxHeight = contentHeight;
button.textContent = "Show Less";
setTimeout(resetHeight, 700) // the timeout is the same as the transition time
}
}
const content = document.getElementById("content")
const wrapper = document.getElementById("content-wrapper");
const button = document.getElementById("show-more");
button.addEventListener("click", toggleText);
This is my first answer on StackOverflow, so if there is anything I can improve
please do let me know.
Related
on a website I'm creating I have some accordions, and each of them has an image at the top. When you open the accordion, there's a description inside, and the image changes to another one. Then when you close the accordion, the image switches back to the first one.
The problem is that I'd like this image change to have a smooth transition, with a fade effect, and right now it's just an abrupt change. How can I do it?
Let's say that the accordion button has an id of "button"; and the tag that contains the first image (which will change to the second image) has an id of "firstimage".
This is the code in Javascript:
let counter = 1;
let button = document.querySelector("#button");
button.addEventListener("click", function () {
let image = document.querySelector("#firstimage");
image.setAttribute(
"src",
"(url of the first image)"
);
counter++;
if (counter > 2) {
counter = 1;
image.setAttribute(
"src",
"(url of the second image)"
);
}
});
Maybe this is something I should edit in the CSS? I already tried adding a transition to the first image in CSS ( transition: all 360ms ease-in-out ) but it didn't work.
You can just put two images on top of one another and set the opacity.
document.querySelector('.wrapper').addEventListener("click", function (e) {
e.currentTarget.classList.toggle("active");
});
.wrapper {
position: relative;
display: inline-block;
}
.wrapper > img + img {
position: absolute;
left:0;
opacity: 0;
transition: opacity 2s ease-in-out;
}
.wrapper.active > img + img {
opacity: 1;
transition: opacity 2s ease-in-out;
}
<div class="wrapper">
<img src="http://placekitten.com/200/300" />
<img src="http://placekitten.com/g/200/300" />
</div>
I'm trying to display the rest of my text with an animation on the height when you click on a button, I managed to do it but the problem is that I can't find a way to make it responsive.. Basically I display a height: 30px and an overflow: hidden.
And I toggle on a class that contains a height: 300px , it looks good in the mobile version but if I increase the resolution of the page the height will become too small.
I thought there might be a way to adapt the height with the width of the screen, or maybe there is another way to hide part of the text?
Below is the code:
Scss:
.about__body{
#include displayFlex($direction: column, $align-item: center);
gap: 20px;
&-content {
height: 60px;
overflow: hidden;
transition: all 400ms ease-in-out;
}
}
.about__body-content-show {
transition: all 400ms ease-in-out;
height: auto;
}
JS:
let btnAbout = document.getElementById("btn--about")
let contentAbout = document.querySelector(".about__body-content")
const onClickShow = () => {
btnAbout.addEventListener('click', (e) => {
e.preventDefault()
contentAbout.classList.toggle('about__body-content-show')
})
}
onClickShow()
You basically can use JS to achieve this and make your container same height as your content
document.getElementById('expand').addEventListener('click', function() {
document.querySelector('.content-holder').style.height = document.querySelector('.content').offsetHeight + 'px';
document.querySelector('.content-holder').classList.toggle('collapsed');
});
a working fiddle: https://jsfiddle.net/sdjhetq1/
I use css to have animation (using transition) in a div. The content of the div is dynamical (can be 1 line or multiple lines).
I have 2 classes I switch to get the animation effect:
.class1{
max-height: 200px;
}
.class2{
max-height: 0;
}
My problem occurs when the I have only 1 line in the div, so there's "delay" until the 1 line disappears (because the height changes from 200px to 0 while the actual size is only 30px).
I tried to use element.style.maxHeight = elem.offsetHeight + "px" to set the max-height size but it didn't work so I want to change max-height in the class (class1 or class2) to fit the actual size.
How can I change the content of a class (I don't want to have: "style = max-height: 100px" in my div)?
You could use the transition in combination with the transform.
Not only because solve your problem, but also because has better performance then change the height.
Doesn't make sense changing the height and using CSS, in terms of performance you can use JS, it is the same.
I did an example for you on jsfiddle because on here seems to do not work.
jQuery(document).ready(function() {
jQuery('.click-me').on('click', function() {
var $this = jQuery(this);
if ($this.hasClass('show')) {
jQuery(this).removeClass('show').addClass('hide');
}
});
});
.hide {
transform: translateY(-100%);
z-index: -1;
}
.show {
transform: translateX(0);
z-index: 0;
}
.animate {
transition: transform 1s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="parent">
<div class="click-me animate show">
<div>one line</div>
</div>
</div>
Pls help me how to open div smoothly.I have add script and html code, its working perfectly but div open suddenly with jerk. I want to open my div "#mapsec" smoothly.
function showhide() {
var div = document.getElementById("mapsec");
if (div.style.display !== "none") {
div.style.display = "none";
}
else {
div.style.display = "block";
}
}
HTML CODE
<h3>Visit us (<i><a onclick="showhide()" id="scrollmap" class="mapimg" style="cursor: pointer;">Map</a></i>)</h3>
<div id="mapsec" style="display: none; clear: both;">
<img
src="http://www.websitesnmore.com.au/wp-content/uploads/2013/06/map-img.jpg"
alt="map-img" width="1245" height="350"
class="alignnone size-full wp-image-4586" />
</div>
You have several ways to do it with jQuery. For example:
function showhide() {
$('#mapsec').slideToggle(200);
}
This will slide the div open or closed. 200 is the speed of the animation in miliseconds.
Check these out:
$('#mapsec').toggle(200); — jQuery.toggle()
$('#mapsec').slideToggle(200); — jQuery.slideToggle()
$('#mapsec').fadeToggle(200); — jQuery.fadeToggle()
Using display does exactly what it says it does: displayor hide elements. You could use jQuerys hide and show functions, but since you are trying to use standard javascript, I'll hand you another solution:
<div id="mapsec">
<!-- Your Contents -->
</div>
Now your CSS:
#mapsec {
max-height: 0;
overflow: hidden;
/* You should prefix the following: */
transition: max-height 500ms;
}
#mapsec.active {
/* Depending on this value, your animatiom will seem faster or shorter */
max-height: 1000px;
}
Now the javascript:
function showhide(){
var div = document.getElementById("mapsec");
if (div.className === "") {
div.className = "active";
} else {
div.className = "";
}
}
What we are using is CSS3's built-in animations to trigger something that looks smoother. We hide the overflow of the box you want to animate - as you want it to be invisible. Then we also set it max-height to 0, so it will appear to have no height whatsoever (I would like to add that any paddings and margins don't get included here and might need to be reset as well).
Now we simple add the active class to the div to animate it.
Heres an improved, more universal, and reusable version of the CSS and javascript:
<div id="mapsec" class="hidden">
<!-- Your Contents -->
</div>
.hidden {
max-height: 0;
overflow: hidden;
transition: max-height 500ms;
}
.hidden.active {
max-height: 1000px;
}
function showhide(id){
var div = document.getElementById(id);
if (div.className === "hidden") {
div.className = "hidden active";
} else {
div.className = "hidden";
}
}
Now you can add hidden to any box and unhide it by doing Unhide(replacing 'id' with the id of the element you want to show).
If you want to use jQuery, we can make it even better and easier (and robuster) by using something jQuery has built-in:
Unhide
Now the toggleClass will add the active class and remove it by itself! This is better, as when you use multiple classes, jQuery will leave them intact (notice we don't actually have to use hidden in this code anymore? As long as it already has hidden, we can leave it alone.)
function showhide(id){
var div = document.getElementById(id);
if (div.className === "hidden") {
div.className = "hidden active";
} else {
div.className = "hidden";
}
}
.hidden {
max-height: 0;
overflow: hidden;
/* You should prefix the following: */
transition: max-height 500ms;
}
.hidden.active {
max-height: 1000px;
}
<div id="mapsec" class="hidden">
<img src="" width="200" height="200" />
</div>
ShowHide
Use jQuery.toggle():
function showhide() {
$('#mapsec').toggle();
}
$( "#mapsec" ).show( "slow" );
This should ease the div in nicely instead of:
div.style.display = "block";
I would mainly agree with somethinghere, but since you animate a div with an image inside, than I would animate height of div and set the image height to 100%. Think that looks better/smoother Fiddle. JS changing class is from the answer, but CSS is:
#mapsec {
height: 0;
overflow: hidden;
-webkit-transition: height 500ms;
transition: height 500ms;
}
#mapsec.active {
height: 200px;
}
#mapsec img {
height: 100%;
width: 100%;
}
My intent is to animate using CSS3 the transition of height of a element when a child div get expanded.
<div id="container">
<div id="content">
<span>Small Conent</span>
<div id="big">
<p>
This is way bigger content, will be visible after you have clicked the
"Expand" button.
</p>
<p>It should animate up to the correct position.</p>
</div>
</div>
<button id="expand">Expand</button>
</div>
I came up with this hack, using max-height. But there are a couple of problems:
The max-height must have a value
The animation will start and stop according to the max-height given value, so if you insert a crazy value like 2000px the animation will have a great delay.
To better illustrate the problem, I created a Fiddle: http://jsfiddle.net/egDsE/3/
The only way of having a precise animation, is to insert the correct value of max-height.
My intention is to calculate using JavaScript (and JavaScript only) what the height of the parent will be once the child is expanded. But of course, I will need to calculate it before the actual transition takes place.
Is this possible? Only pure JS please.
Actually, you don't need to do all of the that cloning and stuff...just give the element height auto, check the size and set the height back to 0. It'll happen so fast the browser has no chance to repaint.
Now, this works like a charm, but the thing is that setting the height in Javascript immediately afterward will cause the transition to fail. I just throw a 100ms timeout around it and then it works fine.
Javascript:
document.getElementById('expand').addEventListener('click', function () {
var el = document.getElementById('big');
if (!el.className) {
el.className = 'expanded';
document.getElementById('expand').innerHTML = 'Retract';
var elH = getHeight(el);
window.setTimeout(function() {
el.style.height = elH+'px';
}, 100);
} else {
el.className = '';
el.style.height = '0';
document.getElementById('expand').innerHTML = 'Expand';
}
});
function getHeight(el) {
el.style.height = 'auto';
elHeight = el.offsetHeight;
el.style.height = '0';
return elHeight;
}
CSS:
#container {
border: 1px solid gray;
padding: 20px;
}
#big {
overflow: hidden;
height: 0;
transition: height 0.5s ease-in-out;
-webkit-transition: height 0.5s ease-in-out;
-moz-transition: height 0.5s ease-in-out;
-o-transition: height 0.5s ease-in-out;
}
HTML: no changes to your markup
<div id="container">
<div id="content"> <span>Small Conent</span>
<div id="big">
<p>This is way bigger content, will be visible after you have clicked the "Expand" button.</p>
<p>It should animate up to the correct position.</p>
</div>
</div>
<button id="expand">Expand</button>
</div>
DEMO
I have updated the Fiddle with the solution proposed in the comments by Bartdude, optimizing it for performances as possible.
http://jsfiddle.net/egDsE/5/
var calculateHeight = function(e) {
var outside = document.getElementById('outside');
var clone = e.cloneNode(true);
outside.appendChild(clone);
var elHeight = outside.offsetHeight;
outside.removeChild(clone);
return elHeight;
}
The outside div have very basic css:
#outside {
position: absolute;
top: -1000;
left: -1000;
}
I won't recommend this solution if image are involved, they would slow down the operation significantly.
not to be that guy but I would use LESS if you don't want to be as intensive and get this functionality