YSbakker
YSbakker

Reputation: 707

JavaScript transition with the display property?

Can I make a certain element fade in when I hover over another one, and make it fade out when my mouse isn't on the element anymore?

I tried adding a transition in the CSS, but that doesn't seem to work (which I already predicted, because it's in fact the JavaScript that makes the div visible using DOM...).

I got the fiddle over here

Upvotes: 0

Views: 129

Answers (3)

blex
blex

Reputation: 25634

At first, I thought about soktinpk's solution. Opacity can be animated with css so it's the best bet.

However, it takes up the space even when it is not shown. To prevent that, you could make it position:absolute. But even then, elements behind it will not be clickable.

Here is a more robust solution with a combination of @soktinpk's ideas

To prevent that, hide it with display:none when it is not visible.

Edit

Actually, visibility:hidden seems to work better when fading back in.

HTML

<div id="button" onmouseover="showMenu()" onmouseout="hideMenu()">
    <!-- placing it inside will allow it to be positioned as wanted -->
    <div id="menu"></div>
</div>

CSS

#button {
    background-color: rgb(0,0,100);
    width: 100px;
    height: 50px;
    margin-top: 50px;
    margin-left: 50px;
    position:relative; // All absolutely positioned elements inside are relative to this element
}

#menu {
    background-color: rgb(0,100,0);
    width: 200px;
    height: 100px;
    opacity:0;
    visibility:hidden;
    transition: opacity 1s;
    -webkit-transition: opacity 1s;
    -moz-transition: opacity 1s;
    -o-transition: opacity 1s;
    position:absolute; // So that it displays at the right position
    top:100%;
    left:0;
}

JS

var time_out;
var menu = document.getElementById("menu");

function showMenu() {
    clearTimeout(time_out);
    menu.style.visibility = "visible";
    menu.style.opacity = 1;
}

function hideMenu() {
    clearTimeout(time_out);
    menu.style.opacity = 0;
    // This will hide it when the animation is over
    time_out = setTimeout(function(){menu.style.visibility = "hidden";},1000);
}

JS Fiddle Demo

Upvotes: 2

soktinpk
soktinpk

Reputation: 3888

Here is a mostly css answer: http://jsfiddle.net/Z7GuR/4/

Instead of using display since that has only two modes (in this case: none and block) you should use opacity. That will give you a smooth transition.

Css:

#menu {
    background-color: rgb(0,100,0);
    width: 200px;
    height: 100px;
    margin-left: 50px;
    // Notice
    opacity: 0;
    transition: opacity 1s;
    -webkit-transition: opacity 1s;
    -moz-transition: opacity 1s;
    -o-transition: opacity 1s;
}

Javascript:

function showMenu() {
    document.getElementById("menu").style.opacity = 1;
}

function hideMenu() {
    document.getElementById("menu").style.opacity = 0;
    // If you want, you can bind an "end" event to css transition and
    // set "display" to none when that happens
}

As some have pointed out, the element will still take up space even after its opacity is set to 0. To prevent this, you can set display to none after the animation has ended, as I said in the example (sorry if this wasn't clear). This is much better than changing the margin, which is a "hacky" solution.

Edit: Okay, the display: none, works, but for some reason, with display: block, the animation is choppy when you fade back in, if it's completely faded out previously (in chrome, at least). So, instead of display: none, I used a combination of position: absolute, and visibility: hidden, to hide the element:

http://jsfiddle.net/Z7GuR/4/

var menu = document.getElementById("menu"), button = document.getElementById("button");

function showMenu() {
    menu.style.opacity = 1;
    // Reset visibility and position
    menu.style.visibility = "visible";
    menu.style.position = "static";
    menu.removeEventListener("transitionend", setDisplayNone, false);
}

function hideMenu() {
    menu.style.opacity = 0;
    // I prefer using transitionend to setTimeout
    // transitionend is more extendable, and it makes more sense to me
    menu.addEventListener("transitionend", setDisplayNone, false);
}

function setDisplayNone() {
    menu.style.visibility = "hidden";
    menu.style.position = "absolute";
}

button.addEventListener("mouseover", showMenu);
button.addEventListener("mouseout", hideMenu);

The only major difference between my answer and the accepted answer is that the text will always be visible (the fading element won't cover it).

Upvotes: 2

webkit
webkit

Reputation: 3369

Here's a pure css solution for your specific html:

fiddle

html

<div id="button" onmouseover="showMenu()" onmouseout="hideMenu()"></div>
<div id="menu"></div>

for the css I used opacity instead of display and added the following:

css

#button:hover ~ #menu,
#menu:hover {
    opacity:1;
    height:100px;
}

Upvotes: 1

Related Questions