I have a simple slideToggle component (taken from here).
You can see the code running in a CodePen here.
I understand the general principle of the code, but there are two lines (both the same) which have me scratching my head as to what they do.
Here is the code for the slideDown
function:
const slideDown = (target, duration = 500) => {
target.style.removeProperty("display");
let display = window.getComputedStyle(target).display;
if (display === "none") display = "block";
target.style.display = display;
const height = target.offsetHeight;
target.style.overflow = "hidden";
target.style.height = 0;
target.style.paddingTop = 0;
target.style.paddingBottom = 0;
target.style.marginTop = 0;
target.style.marginBottom = 0;
// Commenting out this line causes the animation to break
target.offsetHeight;
target.style.boxSizing = "border-box";
target.style.transitionProperty = "height, margin, padding";
target.style.transitionDuration = duration + "ms";
target.style.height = height + "px";
target.style.removeProperty("padding-top");
target.style.removeProperty("padding-bottom");
target.style.removeProperty("margin-top");
target.style.removeProperty("margin-bottom");
window.setTimeout(() => {
target.style.removeProperty("height");
target.style.removeProperty("overflow");
target.style.removeProperty("transition-duration");
target.style.removeProperty("transition-property");
}, duration);
};
Notice this line:
target.offsetHeight;
At first I thought it was a typo, but commenting it out stops the slideDown
animation from working.
The same line occurs in the slideUp
function, but the animation still seems to work if this is commented out.
Can anyone explain why this random expression which appears to do nothing, stops the slideDown
animation from working if it is removed?
Here is the code in a web page in case anyone wants to run it on their machine:
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="utf-8">
<title>SlideToggle</title>
<style>
#target {
padding: 6em 1.5em;
background-color: #ef1;
margin-bottom: 1em;
text-align: center;
color: rgba(0, 0, 0, 0.65);
font-weight: 700;
border-radius: 5px;
}
#target h1 {
max-width: 500px;
font-size: 1.5;
margin: 0 auto;
line-height: 1.618;
font-weight: regular;
}
.triggers {
text-align: center;
}
</style>
</head>
<body>
<div id="target">
<h1>Pure JavaScript SlideToggle / SlideUp / slideDown</h1>
</div>
<div class="triggers">
<button id="triggerUp">slideUp</button>
<button id="triggerDown">slideDown</button>
<button id="triggerToggle">slideToggle</button>
</div>
<script>
const slideUp = (target, duration = 500) => {
target.style.transitionProperty = "height, margin, padding";
target.style.transitionDuration = duration + "ms";
target.style.boxSizing = "border-box";
target.style.height = target.offsetHeight + "px";
// Seems you can get away with commenting out the next line
target.offsetHeight;
target.style.overflow = "hidden";
target.style.height = 0;
target.style.paddingTop = 0;
target.style.paddingBottom = 0;
target.style.marginTop = 0;
target.style.marginBottom = 0;
window.setTimeout(() => {
target.style.display = "none";
target.style.removeProperty("height");
target.style.removeProperty("padding-top");
target.style.removeProperty("padding-bottom");
target.style.removeProperty("margin-top");
target.style.removeProperty("margin-bottom");
target.style.removeProperty("overflow");
target.style.removeProperty("transition-duration");
target.style.removeProperty("transition-property");
}, duration);
};
const slideDown = (target, duration = 500) => {
target.style.removeProperty("display");
let display = window.getComputedStyle(target).display;
if (display === "none") display = "block";
target.style.display = display;
const height = target.offsetHeight;
target.style.overflow = "hidden";
target.style.height = 0;
target.style.paddingTop = 0;
target.style.paddingBottom = 0;
target.style.marginTop = 0;
target.style.marginBottom = 0;
// Commenting out the next line causes the animation to break
target.offsetHeight;
target.style.boxSizing = "border-box";
target.style.transitionProperty = "height, margin, padding";
target.style.transitionDuration = duration + "ms";
target.style.height = height + "px";
target.style.removeProperty("padding-top");
target.style.removeProperty("padding-bottom");
target.style.removeProperty("margin-top");
target.style.removeProperty("margin-bottom");
window.setTimeout(() => {
target.style.removeProperty("height");
target.style.removeProperty("overflow");
target.style.removeProperty("transition-duration");
target.style.removeProperty("transition-property");
}, duration);
};
const slideToggle = (target, duration = 500) => {
if (window.getComputedStyle(target).display === "none") {
return slideDown(target, duration);
}
return slideUp(target, duration);
};
document.getElementById("triggerUp").addEventListener("click", function () {
slideUp(document.getElementById("target"), 300);
});
document.getElementById("triggerDown").addEventListener("click", function () {
slideDown(document.getElementById("target"), 300);
});
document.getElementById("triggerToggle").addEventListener("click", function () {
slideToggle(document.getElementById("target"), 300);
});
</script>
</body>
</html>