in spectrum in spectrum - 7 months ago 28
HTML Question

How to smoothly fade in/ fade out an element after giving it a display:none value

I'm aware of the many questions here on Stack Overflow similar to this one which all get resolved by using

visibility:hidden
instead of the
display:none
property. The problem I have is I think I must use
display:none
because I need to fill the space of the div being hidden with an alternate div,
visibility:hidden
would just preserve that space while making it invisible.

MY GOAL: after the + button is clicked the
nav
element correctly fades out. After this animation I have a JavaScript line that counts 500 milliseconds and then gives the faded div a class containing
display:none
.

The problem is when the now - button is clicked, I give the element back its
display:block
property and remove the class that was giving it its blur/fade effect. But instead of a nice fade/in transition, the element just instantly pops back on the screen. No animation.

I'm at a loss for how to fix this while continuuing to use the
display:none
property. Thanks for the help and I'm not using any libraries like jQuery, just plain vanilla Javascript.



var expand = document.getElementById("expansion");

function removeElm() {
"use strict";
document.querySelector("nav").classList.add("removed");
document.querySelector("#description").classList.remove("removed");
}

function expandF() {
"use strict";
var navLi = document.querySelectorAll("li"), i;

if (!document.querySelector("nav").classList.contains("out")) {
document.querySelector("nav").classList.add("out");
document.querySelector("body").style.background = "#dff";
document.getElementById("expansion").innerHTML = "-";
document.getElementById("expansion").style.background = "#f00";

for (i = 0; i < navLi.length; i++) {
navLi[i].classList.add("rsHover");
}
setTimeout(removeElm, 500);
} else {
document.querySelector("nav").classList.remove("removed");
document.querySelector("#description").classList.add("removed");
document.querySelector("nav").classList.remove("out");
document.querySelector("body").style.background = "#fff";
document.getElementById("expansion").innerHTML = "+";
document.getElementById("expansion").style.background = "#222";

for (i = 0; i < navLi.length; i++) {
navLi[i].classList.remove("rsHover");
}
}
}

expand.addEventListener("click", expandF);

/*///////////////////////////////// __NAV__ /////////////////////////////////*/
nav {
display: inline-block; position: relative; top: 50%; right: 19px;
-webkit-transform: translateY(-50%); transform: translateY(-50%); margin: auto
}
nav ul:after { content: ""; display: block; clear: both } /* << clearfix */

nav ul { font-size: 100%; text-transform: uppercase; margin: 0; padding: 0 }
nav li { width: 150px; height: 150px; list-style: none; float: left; margin: 5px}
nav li:hover { background: #055; color: #eee; cursor:pointer }
nav span {
display: block; position: relative; top: 50%; -webkit-transform: translateY(-50%);
transform: translateY(-50%)
}
/*///////////////////////////////// SECTION /////////////////////////////////*/
#description {
display: inline-block; position: relative; top: 50%; right: 19px;
-webkit-transform: translateY(-50%); transform: translateY(-50%); margin: auto
}
/*///////////////////////////////// _MISC__ /////////////////////////////////*/
.removed { display: none !important }
.rsHover:hover { background: #dff }
.out {
-webkit-filter: blur(60px); filter: blur(60px); color: #fff;
-webkit-transform: scale(0.1, 0.9); transform: scale(0.1, 0.9);
-webkit-transform: translateY(-50%); transform: translateY(-50%); font-size: 110%;
}
/*///////////////////////////////// _ANIM__ /////////////////////////////////*/
body{ -webkit-transition:2s ease; transition:2s ease }

nav{
-webkit-transition:color 1s ease, -webkit-filter 1s ease, -webkit-transform 1s ease;
transition:color 1s ease, -webkit-filter 1s ease, -webkit-transform 1s ease;
transition:filter 1s ease, color 1s ease, transform 1s ease;
transition:filter 1s ease, color 1s ease, transform 1s ease, -webkit-filter 1s ease,
-webkit-transform 1s ease;
}

<head>
<style>
html,body { height: 100%; text-align: center; color: #222; margin: 0 }
#expansion {
float:left; position: relative; top: 50%; -webkit-transform: translateY(-50%);
transform: translateY(-50%); width: 28px; height: 28px; padding: 5px;
margin: auto; color: #666; font-size: 150%
}
#expansion:hover { background: #222; color: #eee; cursor:pointer; }
</style>
</head>

<body>
<div id="expansion">+</div>
<nav>
<ul>
<li><span>one</span>
</li>
<li><span>two</span>
</li>
</ul>
</nav>
<section id="description" class="removed">
<h1>about web</h1>
<p>
WEB is a reference of...
</p>
</section>
</body>




Answer

You need to force the browser to render the element after setting display: block to make sure the element is in the document flow, as otherwise it won't do any transitions or animations. Use reflow:

Your element in current hidden (display: none) state:

<div style="display: none; opacity: 0; transition: opacity 500ms"></div>

JS to make it in flow and then transition to opacity: 1:

div.style.display = 'block';
div.clientHeight; // Forces the browser to "reflow"
div.style.opacity = 1; // Now the element will transition from opacity: 0 to opacity: 1

Where div is the HTMLElement object. Note that opacity is just an example.

I strongly suggest you read this to understand more (as it's a really complex topic): http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/

edit: changed currentHeight to clientHeight.