user6052202
user6052202

Reputation:

Opacity transition works on fade out, but not fade in

This is frustrating me to no end. Before I post the code, here's a summary:

The goal, in simple terms: when I double click X, I want it to fade out; when I click Y, I want X to fade in.

The method: I'm using CSS to create the actual fade-in and fade-out "animations." I'm using JavaScript to apply the classes when necessary using a little trickery.

The problem: the fade-in transition doesn't work -- the element just appears instantly. What is driving me insane is the fact that the fade-in, when instantly added back onto a faded-out object, works perfectly. I'll explain this better as a comment in the JS code.

(Yes, I've added opacity: 1 and transition: opacity onto the base elements. It had no effect at all.)

The code:

CSS

*.fade-out {
    opacity: 0;
    transition: opacity 400ms;
}
*.fade-in {
    opacity: 1;
    transition: opacity 400ms;
}
*.hide {
    display: none;
    visibility: hidden;
}

JavaScript

$( '#ArtistEmblem' ).on( 'dblclick', function() {
    fadeOut($( '#ArtistEmblem' ));
    fadeIn($( '#btnShowLogo' ));
});
$( '#btnShowLogo' ).on( 'click', function() {
    fadeOut($( '#btnShowLogo' ));
    fadeIn($( '#ArtistEmblem' ));
});

function fadeOut(element) {
    element.addClass( 'fade-out' );

    setTimeout( function () {
        element.addClass( 'hide' );

        /*
        * I tried immediately adding the 'fade-in' class here
        * and it worked -- as soon as the element faded out, it faded
        * back in (using the CSS transition). However, outside of this,
        * it REFUSES to work; everything appears instantly
        */

        console.log('timer triggered');
    }, 400);
}

function fadeIn(element) {
    element.removeClass( 'hide' );
    element.removeClass( 'fade-out' );
    element.addClass( 'fade-in' );
}

Relevant HTML

<div id="ArtistEmblem">
    <img src="img/logo_artist_2.png" />
</div>

<div id="PopMenu" class="collapse">
    <article>
        <header>
            <b>Debug Menu</b>
        </header>
        <section>
            <button id="btnOpenOverlay">Open Overlay</button>
            <button id="btnShowLogo" class="hide">Show Logo</button>
            <button id="btnClose">Close Menu</button>
        </section>
    </article>
</div>

I apologize if this is something obvious but I've wasted far too much time trying to solve it. I am also open to better, faster, or more efficient solutions if that would be the best answer. Thanks in advance!

Upvotes: 0

Views: 3789

Answers (3)

JoshMoxey
JoshMoxey

Reputation: 36

I know you're asking for a JS heavy answer, but I highly recommend toggling a class of "active", "open" or something similar and using CSS with the transition. Less is more here.

Here's an example fiddle of something I've transitions not only the opacity, but also the z-index. That's the key with these transitions if you intend on having any elements below such as buttons that require hovering, clicking, etc.

JS Fiddle

Key parts:

.container {
  z-index: -1;
  opacity: 0;
  transition: z-index .01s 1s, opacity 1s;
}

.container.active {
  transition: z-index 0s, opacity 1s;
  z-index: 500;
  opacity: 1;
}

EDIT

I was just messing around with this type of thing for my own project, and observing how beautiful Stripe handles their navigation bar. Something so simple changes everything, and that's pointer-events. If you're okay with its support, (notable no ie. 10) this is infinitely easier to integrate. Here's another fiddle of the simulation in a nav bar.

The key part is pointer-events: none, as it ignores click events if set to none, almost as if it wasn't there, yet visibly it is. I highly recommend this.

https://jsfiddle.net/joshmoxey/dd2sts7d/1/

Upvotes: 1

dhilt
dhilt

Reputation: 20744

The problem is that the initial opacity of "hidden" element is 1 by default. You just need to set it to 0. And also remove display: none

*.hide {
    opacity: 0;
}

Also I would do a little refactoring and remove setTimeout:

$('#ArtistEmblem').on('click', function() {
    fade($('#btnShowLogo'), $(this));
});
$('#btnShowLogo').on('click', function() {
    fade($('#ArtistEmblem'), $(this));
});

function fade(inElement, outElement) {
    inElement.removeClass('hide');
    inElement.addClass('fade-in');

    outElement.removeClass('fade-in');
    outElement.addClass('fade-out');
}

If you don't want the hidden element to occupy space and you want it to be displayed-none, then you need to set display: block before starting the fadeOut.

Upvotes: 1

Nandu Kalidindi
Nandu Kalidindi

Reputation: 6280

Here is an example using Javascript Animate API. Animate API is not supported in IE/Edge though.

var element = document.getElementById("fade-in-out")

var button = document.getElementById("x")

button.addEventListener("click", function(event) {
  element.animate([{opacity: 1, visibility: "visible"},{opacity: 0, visibility: "hidden"}], {duration: 2000})
  
  setTimeout(function() { element.remove() }, 2000)
})

button.addEventListener("dblclick", function(event) {
  element && element.animate([{opacity: 0}, {opacity: 1}], {duration: 2000})
})
<input id="x" type="button" value="Click here" />
<div id="fade-in-out"> FADE ME </div>

Upvotes: 0

Related Questions